﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.IO;
using XML_Reader.Properties;

namespace XML_Reader
{
    public partial class Form1 : Form
    {
        public String[] OpendFilesName;
        public int curFilesNum = 0;
        private bool mutex = true;                          //互斥访问变量
        private bool fruitMutex = true;                     //互斥访问变量，水果种类数目

        private bool mutexLoadFinish = false;               //标识数据是否读入完成
        private bool mutexSaveFinish = true;                //标识数据是否导出完成
        private int saveProcess = 0;                        //标识数据的保存进度

        //pictureBox界面的绘制相关
        private Graphics g;
        private Pen pen1;
        public int width, border;                           //tileMap块的宽度

        int[] RL;
        Rectangle toolsRect, tileMapRect;                   //记录工具块、tileMap图 的表示区域   
        Point toolsPostion, tileMapPostion, toolSelect;     //记录在工具条中、tileMap中行列位置、在工具条中的选中位置
        int[,] toolsData, tileMapData;                      //工具栏中的块数值、图块数据
        int[,] fruitData;                                   //记录各位置处的水果类型数据
        Random rnd = new Random();                          //随机数
        int numOfFruit;                                     //水果类型数
        bool[] fruitSelect;                                 //标标识对应的各种水果是否选中

        Point[,] CA;                                        //水果接收位置记录，第一二维标志传送位置，记录接收水果的坐标
        int[, ,] CA_num;                                    //传送接收位置标号记录，第一二维标志位置，第三维传送和接收数值标号
        int CA_count = 0;                                   //计数传送和接收块的总数
        Point preSite;                                      //记录前一个传送位置的坐标
        
        bool isEnglish = true;                              //标志属性名称是否为英文显示

        private Image[,] targeFruit =                       //光圈水果和水果标签
        {
            {Resources.fruit21, Resources.fruit22, Resources.fruit23, Resources.fruit24, Resources.fruit25, Resources.fruit26},
            {Resources.h1, Resources.h2, Resources.h3, Resources.h4, Resources.h5, Resources.h6},
            {Resources.v1, Resources.v2, Resources.v3, Resources.v4, Resources.v5, Resources.v6}
        };

        private Image[,] toolsPic = {
                                       { Resources.shade1, Resources.ice1, Resources.ice2, Resources.stone, Resources._lock ,Resources.eraser,Resources.convery },
                                       { Resources.fruit1, Resources.fruit2, Resources.fruit3, Resources.fruit4, Resources.fruit5, Resources.fruit6, Resources.accept},
                                       { Resources.hat, Resources.buttle, Resources.sun, Resources.light, Resources.horizental, Resources.vertical, Resources.birth }
                                   };

        private Image unSelcet = Resources.unSelect;  //斜杠图标，表示不可用

        private Cursor[,] mouseIcon;                         //鼠标图标数组，使用toolsPic中的图像创建鼠标图标

        public Form1()
        {
            InitializeComponent();

            comboBox1.Text = "Classic moves";   //初始化列表项
        }

        private void button2_Click(object sender, EventArgs e)
        {
            ReadXML_NodeAttrribute("D:\\data.XML", "Map", "CellHeight");
            ReadXML_NodeAttrribute("D:\\data.XML", "Map/BuildItem", "name");
            //ReadXML("D:\\data.XML");

            ReadXML_NodeText("D:\\data.XML", "Map");
            ReadXML_NodeText("D:\\data.XML", "Map/PhysicalLayer");
        }

        private void button3_Click(object sender, EventArgs e)
        {
            writeXML("D:\\bookstore.xml");
        }

        //读取XML
        private void ReadXML(String file)
        {
            //载入XML文档
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(file);


            XmlNode root = xmlDoc.SelectSingleNode("Map");//查找<bookstore>
            XmlElement Node = (XmlElement)root;
            String str = Node.GetAttribute("CellHeight"); //CellWidth

            MessageBox.Show("宽度值：" + str + "", "消息", MessageBoxButtons.OK, MessageBoxIcon.Information);

            //root.SelectSingleNode()
            XmlNode Node2 = root.SelectSingleNode("PhysicalLayer");        //查找子节点
            XmlElement Elem = (XmlElement)Node2;
            MessageBox.Show("获取数据：" + Elem.InnerText, "消息", MessageBoxButtons.OK, MessageBoxIcon.Information);

        }

        //写入XML
        private void writeXML(String file)
        {
            //载入XML文档
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(file);

            //修改XML
            XmlNode root = xmlDoc.SelectSingleNode("bookstore");//查找<bookstore>
            {
                XmlElement xe1 = xmlDoc.CreateElement("book");  //创建一个<book>节点
                xe1.SetAttribute("genre", "李赞红");            //设置该节点genre属性
                xe1.SetAttribute("ISBN", "2-3631-4");           //设置该节点ISBN属性
                {
                    XmlElement xesub1 = xmlDoc.CreateElement("title");
                    xesub1.InnerText = "CS从入门到精通";        //设置文本节点
                    xe1.AppendChild(xesub1);                    //添加到<book>节点中

                    XmlElement xesub2 = xmlDoc.CreateElement("author");
                    xesub2.InnerText = "候捷";
                    xe1.AppendChild(xesub2);

                    XmlElement xesub3 = xmlDoc.CreateElement("price");
                    xesub3.InnerText = "58.3";
                    xe1.AppendChild(xesub3);
                }
                root.AppendChild(xe1);                          //添加到<bookstore>节点中
            }

            //保存修改到XML
            xmlDoc.Save(file);
            MessageBox.Show("写入XML完成", "消息", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        //获取XML文件，节点属性值,用法：
        //ReadXML_Attrribute("D:\\data.XML", "Map", "CellHeight");     根节点
        //ReadXML_Attrribute("D:\\data.XML", "Map/BuildItem", "name"); 子节点
        String ReadXML_NodeAttrribute(String file, String nodePath, String attr)
        {
            String str = "";
            try
            {
                //载入XML文档
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load(file);

                XmlNode Node = xmlDoc.SelectSingleNode(nodePath);   //查找节点
                XmlElement Elemnet = (XmlElement)Node;              //转化为XML元素

                str = Elemnet.GetAttribute(attr);                   //获取节点属性值
            }
            catch (Exception e)
            {
                String tmp = "获取XML文件，节点属性值出错！ \n1、请确保文件\n“" + file + "”存在，且其格式无误\n2、请确保节点“" + nodePath + "”和节点属性“" + attr + "”在XML文件中确实存在";
                MessageBox.Show(tmp, "消息", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }

            return str;
        }

        //获取XML文件，节点数据,用法
        //ReadXML_NodeText("D:\\data.XML", "Map");                  根节点
        //ReadXML_NodeText("D:\\data.XML", "Map/PhysicalLayer");    子节点
        String ReadXML_NodeText(String file, String nodePath)
        {
            String str = "";
            try
            {
                //载入XML文档
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load(file);

                XmlNode Node = xmlDoc.SelectSingleNode(nodePath);   //查找节点
                XmlElement Elemnet = (XmlElement)Node;              //转化为XML元素

                str = Elemnet.InnerText;                     //获取节点数据
            }
            catch (Exception e)
            {
                String tmp = "获取XML文件，节点数据出错！ \n1、请确保文件\n“" + file + "”存在，且其格式无误\n2、请确保节点“" + nodePath + "”在XML文件中确实存在";
                MessageBox.Show(tmp, "消息", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            return str;
        }

        //打开XML文件
        private void button1_Click(object sender, EventArgs e)
        {
        }

        //DialogResult dr = MessageBox.Show("你确定吗？", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
        //if (dr == DialogResult.OK)
        //{
        //    //确定
        //}


        //从文件"D:\\data.XML"中提取数据
        private String ExtractionData(String filePath)
        {
            //提取所需数据
            String data = "";
            int width = Int16.Parse(ReadXML_NodeAttrribute(filePath, "Map", "MapWidth"));     //读取宽度属性值
            int height = Int16.Parse(ReadXML_NodeAttrribute(filePath, "Map", "MapHeight"));   //读取高度属性值

            String dataTmp = ReadXML_NodeText(filePath, "Map/PhysicalLayer");                 //读取数据
            String[] dataTmp2 = dataTmp.Split(',');

            //转化成指定格式的数据
            for (int h = 0; h < height; h++)
            {
                data += "[";                            //对于每一行
                for (int w = 0; w < width; w++)
                {
                    data += dataTmp2[h * width + w].Trim();
                    if (w != width - 1) data += ",";    //不是该行最后一个数据
                }
                data += "]";
                if (h != height - 1) data += ",";
            }

            return data;
        }

        //从文件"D:\\data.XML"中提取数据转化为规整化的字符串，XML文件形如：
        //<?xml version="1.0" encoding="GB2312"?>
        //<Map phonetype="0" authorname="yangziqing" oriname="新工程" oriauthor="yangziqing" mapremark="飞机" maptype="0" mapdirection="0" mapcolor="1" CellHeight="32" CellWidth="32" 
        //MapHeight="8" MapWidth="8" LvlName="001">
        //    <MapItem name="001"/>
        //    <BuildItem name="101"/>
        //    <GrounData>0,0,1,1,1,0,0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,</GrounData>
        //    <BuildData>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,</BuildData>
        //    <PhysicalLayer>
        //    0,0,2,2,2,0,0,0,0,2,2,2,2,2,0,0,0,2,2,2,2,2,0,0,0,2,2,2,2,2,0,0,0,0,2,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,</PhysicalLayer>
        //</Map>
        private String ExtractionData2(String filePath)
        {
            //提取所需数据
            String data = "";
            int width = Int16.Parse(ReadXML_NodeAttrribute(filePath, "Map", "MapWidth"));     //读取宽度属性值
            int height = Int16.Parse(ReadXML_NodeAttrribute(filePath, "Map", "MapHeight"));   //读取高度属性值

            String dataTmp = ReadXML_NodeText(filePath, "Map/PhysicalLayer");                 //读取该节点的所有数据
            String[] dataTmp2 = dataTmp.Replace("-1", "0").Split(',');                        //分割为单独的项   //@@@关卡编辑器的默认背景数值

            int maxNum = getMaxNum(dataTmp2);           //获取最大数值，用于规整化显示输出

            //转化成指定格式的数据
            for (int h = 0; h < height; h++)
            {
                for (int w = 0; w < width; w++)
                {
                    int index = h * width + w;          //对应一维数组中的位置
                    String strTmp = dataTmp2[index].Trim();                         //去除空格

                    int dataNum = strTmp.Equals("") ? 0 : Int32.Parse(strTmp);      //转化为数值

                    data += ((dataNum>=0 ? " ": "") + dataNum);                      //添加到串中
                    if (w != width - 1) data += ",";    //不是该行最后一个数据
                    data += SpaceFill(dataNum, maxNum); //规整化
                }
                if (h != height - 1) data += ";\r\n";   //对于非最后一行换行显示
            }
            return data;
        }


        //从TXT文件中提取"tileMap"属性值
        private String ExtraTXT_tileMap(String filePath)
        {
            String data = ExtraTXT_Nodedata(filePath, "tileMap");   //从文件中提取节点"tileMap"的相关数据
            return RegularizationTileMap(data);                     //输出规整化后的字符串
        }

        //从TXT文件中提取"portals"属性值
        private String ExtraTXT_portals(String filePath)
        {
            String data = ExtraTXT_Nodedata(filePath, "portals");   //从文件中提取节点"tileMap"的相关数据
            return Regularization_portals(data);                    //输出规整化后的字符串
        }

        //从TXT文件中提取其它的各种属性值
        private void ExtraTXT_Orthers(String filePath)
        {
            //读取属性值
            String gameModeName = ExtraTXT_Nodedata(filePath, "gameModeName", 1);
            String numberOfColours = ExtraTXT_Nodedata(filePath, "numberOfColours").Replace(",", "");

            String protocolVersion = ExtraTXT_Nodedata(filePath, "protocolVersion", 1);
            String randomSeed = ExtraTXT_Nodedata(filePath, "randomSeed").Replace(",", "");
            String scoreTargets = ExtraTXT_Nodedata(filePath, "scoreTargets").Replace(",", " ").Replace("[", " ").Replace("]", " ").Trim();

            String ingredientSpawnDensity = ExtraTXT_Nodedata(filePath, "ingredientSpawnDensity").Replace(",", "");
            String ingredients = ExtraTXT_Nodedata(filePath, "ingredients").Replace(",", " ").Replace("[", " ").Replace("]", " ").Trim();
            String moveLimit = ExtraTXT_Nodedata(filePath, "moveLimit").Replace(",", "").Replace("}", "").Trim();
            if (moveLimit.Equals("")) moveLimit = ExtraTXT_Nodedata(filePath, "timeLimit").Replace(",", "").Replace("}", "").Trim();

            String numIngredientsOnScreen = ExtraTXT_Nodedata(filePath, "numIngredientsOnScreen").Replace(",", "").Replace("}", "").Trim();

            String ingredientsFruit = ExtraTXT_Nodedata(filePath, "ingredientsFruit").Replace(" ", "").Replace("],[", "; ").Replace("[", "").Replace("]],", "").Replace("],", "").Replace("]", "");     //收集水果属性
            String levelDifficulty = ExtraTXT_Nodedata(filePath, "levelDifficulty").Replace(" ", "").Replace("],[", "; ").Replace("[", "").Replace("]],", "").Replace("]", "");       //关卡难度属性


            setSwitch(getOneDiementionData("switchs", filePath));       //设置开关的选中状态

            //显示属性值
            selectMode(gameModeName);
            textBox3.Text = numberOfColours;

            comboBox4.Text = protocolVersion;
            textBox4.Text = randomSeed;
            textBox5.Text = scoreTargets;

            textBox8.Text = ingredientSpawnDensity;
            textBox9.Text = ingredients;
            textBox6.Text = moveLimit;
            textBox10.Text = numIngredientsOnScreen;

            textBox15.Text = ingredientsFruit;
            textBox16.Text = levelDifficulty;

            ExtraFruitData(filePath);           //提取水果数据

            checkBox16_CheckedChanged(null, null);              //刷新工具栏的显示
        }

        //根据键值key从文件中提取一维数据
        private int[] getOneDiementionData(String key, String filePath)
        {
            try
            {
                String str = ExtraTXT_Nodedata(filePath, key).Replace("],", "").Replace("[", "").Replace("]", "").Trim();
                String[] strs = str.Split(',');

                int[] data = new int[strs.Length];
                for (int i = 0; i < strs.Length; i++)
                {
                    data[i] = Int32.Parse(strs[i].Trim());
                }
                return data;
            }
            catch (Exception ex)
            {
                //MessageBox.Show("读取开关状态异常！");
                return null;
            }
        }

        //选择游戏模式
        private void selectMode(String gameModeName)
        {
            String[] modeTextEN = { "Classic moves", "Classic", "Drop down", "Drop down fruit", "Light up" };
            for (int i = 0; i < modeTextEN.Length; i++)
                if (gameModeName.Equals(modeTextEN[i]))
                {
                    comboBox1.SelectedIndex = i;
                    break;
                }
        }

        /// <summary>
        /// 提取出水果数据
        /// </summary>
        private void ExtraFruitData(String filePath)
        {
            int[,] tmp = ExtraTwoDimentionData(filePath, "fruitData", -1);  //提取水果数据
            if (tmp != null)                                                //成功提取数据
            {
                fruitData = tmp;
            }
        }

        /// <summary>
        /// 从JSON文本串中，提取二维数组数据成用，；分隔的字符串
        /// </summary>
        private String ExtraTwoDimentionData(String filePath, string target)
        {
            String data = ExtraTXT_Nodedata(filePath, target);      //从文件中提取节点 target 的相关数据
            data = data.Replace(" ", "").Replace("],[", ";").Replace("]],", "").Replace("],", "").Replace("[", "");
            return data;
        }

        /// <summary>
        /// 从JSON文本串中，提取二维数组数据，默认初始化数值为defaultNum
        /// </summary>
        private int[,] ExtraTwoDimentionData(String filePath, string target, int defaultNum)
        {
            int[,] data = null;

            try
            {
                String tmp = ExtraTwoDimentionData(filePath, target);

                if (tmp.Trim().Equals("")) return null;                                 //属性值为空校验

                String[] strArray = tmp.Split(';');
                for (int i = 0; i < strArray.Length; i++)
                {
                    String[] numArray = strArray[i].Split(',');
                    if (data == null) data = new int[strArray.Length, numArray.Length];  //此处仅适用于规整化的矩形数组

                    for (int j = 0; j < numArray.Length; j++)
                    {
                        try { data[i, j] = numArray[j].Equals("") ? defaultNum : Int32.Parse(numArray[j]); }
                        catch (Exception e) { data[i, j] = defaultNum; }
                    }
                }
            }
            catch (Exception e1) 
            { 
                data = null; 
            }

            return data;
        }


        //默认获取属性：之后的第一个子串为其数据部分
        private String ExtraTXT_Nodedata(String filePath, String target)
        {
            return ExtraTXT_Nodedata(filePath, target, 0);
        }

        //从filePath对应的TXT文件中提取属性名为target的数据,TXT文件格式形如：
        //{"gameModeName":"Classic moves","numberOfColours":6,"portals":[],"protocolVersion":"0.1","randomSeed":0,"scoreTargets":[1500,2000,3000],
        //"tileMap":[[18,0,18,18,18,18,18,0,18],[2,0,2,2,2,2,2,0,2],[2,18,2,2,2,2,2,18,2],[2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2],
        //[2,2,2,2,2,2,2,2,2],[2,0,2,2,2,2,2,0,2],[2,0,2,2,2,2,2,0,2]],"moveLimit":15}
        private String ExtraTXT_Nodedata(String filePath, String target, int postion) //属性之后：第postion个子串位置为其数据部分
        {
            //提取所需数据
            String targetTmp = "";

            //获取文件内容
            if (!System.IO.File.Exists(filePath)) return targetTmp;             //如果文件不存在则退出
            System.IO.StreamReader file1 = new System.IO.StreamReader(filePath);//读取文件中的数据

            string fileText = file1.ReadToEnd();                                //读取文件中的全部数据
            file1.Close();
            file1.Dispose();


            //转化字符串样式
            String[] strTmp1 = fileText.Split(':');                             //分割
            for (int i = 0; i < strTmp1.Length - 1; i++)
            {
                String[] strTmp2 = strTmp1[i].Split('"');                       //再次分割
                targetTmp = strTmp2[strTmp2.Length - 2].Trim();                 //获得属性名

                if (targetTmp.Equals(target))
                {
                    strTmp2 = strTmp1[i + 1].Split('"');                        //分割下一个串
                    targetTmp = strTmp2[postion].Trim();                        //获取目标串

                    return targetTmp;                                           //获取串"[[18,0,18,18,18,18,18,0,18],[2,0,2,2,2,2,2,0,2],[2,18,2,2,2,2,2,18,2],[2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2],
                    //[2,2,2,2,2,2,2,2,2],[2,0,2,2,2,2,2,0,2],[2,0,2,2,2,2,2,0,2]],"
                }
                targetTmp = "";
            }
            return targetTmp;
        }

        //portals属性串规整化,使其显示时规整分布，待规整字符串型如： "[[[0,3],[0,5]],[[1,3],[1,5]],[[7,3],[7,5]],[[8,3],[8,5]]],"
        private String Regularization_portals(String data0)
        {
            String dataTmp = "";

            String data = data0;
            if (data.Replace(",", "").Replace("[", "").Replace("]", "").Trim().Equals("")) return dataTmp; //"portals"= "[],"

            data = data0.Replace("\r\n", "");                               //去除换行符
            data = data.Trim().Replace("]],", ";\r\n");                     //转化样式
            data = data.Trim().Replace("],", ". ");
            data = data.Trim().Replace("[", "");                            //去除字符
            data = data.Trim().Replace("]", "");                            //此时形如: data = 1,0. 1,2; 6,0. 6,2; 2,2. 2,4; 3,2. 3,4; 4,2. 4,4;  5,2. 5,4;  分号处换行

            //return data;


            String[] strRow = data.Replace("\r\n", "").Split(';');          //去除换行符号并按分号分割

            //获取最大值
            int maxNum = 0;
            for (int r1 = 0; r1 < strRow.Length; r1++)
            {
                strRow[r1] = strRow[r1].Trim();                             //去除两端空格
                if (strRow[r1].Equals("")) continue;                        //获取到空串则跳过

                String[] strLine = strRow[r1].Split('.');
                for (int l1 = 0; l1 < strLine.Length; l1++)
                {
                    strLine[l1] = strLine[l1].Trim();                       //去除两端空格
                    if (strLine[l1].Equals("")) continue;                   //获取到空串则跳过

                    String[] strLine2 = strLine[l1].Split(',');
                    for (int l2 = 0; l2 < strLine2.Length; l2++)
                    {
                        String str = strLine2[l2].Trim();
                        int num = Math.Abs(str.Equals("") ? 0 : Int32.Parse(str));    //转化为数值     
                        maxNum = maxNum > num ? maxNum : num;               //获取最大值
                    }
                }
            }

            //规整化
            for (int r = 0; r < strRow.Length; r++)
            {
                strRow[r] = strRow[r].Trim();                               //去除两端空格
                if (strRow[r].Equals("")) continue;                         //获取到空串则跳过

                String[] strLine = strRow[r].Split('.');
                for (int l1 = 0; l1 < strLine.Length; l1++)
                {
                    strLine[l1] = strLine[l1].Trim();                       //去除两端空格
                    if (strLine[l1].Equals("")) continue;                   //获取到空串则跳过

                    String[] strLine2 = strLine[l1].Split(',');
                    for (int l2 = 0; l2 < strLine2.Length; l2++)
                    {
                        String str = strLine2[l2].Trim();
                        int num = str.Equals("") ? 0 : Int32.Parse(str);    //转化为数值  
                        dataTmp += ((num>=0 ? " " : "") + num);              //添加到字符串
                        if (l2 != strLine2.Length - 1) dataTmp += ",";      //不是该行最后一个数据
                        dataTmp += SpaceFill(num, maxNum);                  //规整化
                    }
                    dataTmp += " ";
                    if (l1 != strLine.Length - 1) dataTmp += ".";       //不是该行最后一个数据
                }
                if (r != strRow.Length - 1 && !(r == strRow.Length - 2 && strRow[strRow.Length - 1].Trim().Equals("")))
                    dataTmp += ";\r\n";                                     //对于非最后一行换行显示，若最后一行为空则提前一行进行判断
            }

            return dataTmp;
        }

        //TileMap属性串规整化,使其显示时规整分布，待规整字符串型如： "[[18,0,18,18,18,18,18,0,18],[2,0,2,2,2,2,2,0,2],[2,18,2,2,2,2,2,18,2],[2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2],
        //[2,2,2,2,2,2,2,2,2],[2,0,2,2,2,2,2,0,2],[2,0,2,2,2,2,2,0,2]],"
        private String RegularizationTileMap(String data0)
        {
            String dataTmp = "";

            String data = data0.Replace("\r\n", "");                        //去除换行符
            data = data.Trim().Replace("],", ";\r\n");                      //转化样式
            data = data.Trim().Replace("[", "");                            //去除字符
            data = data.Trim().Replace("]", "");                            //此时形如data = 1,0,0,1;2,0,0,1;1,1,0,1;

            String[] strRow = data.Split(';');

            //获取最大值
            int maxNum = 0;
            for (int r = 0; r < strRow.Length; r++)
            {
                strRow[r] = strRow[r].Trim();                               //去除两端空格
                if (strRow[r].Equals("")) continue;                         //获取到空串则跳过

                String[] strLine = strRow[r].Split(',');
                foreach (String str in strLine)
                {
                    int num = Math.Abs(str.Trim().Equals("") ? 0 : Int32.Parse(str.Trim()));  //转化为数值     
                    maxNum = maxNum > num ? maxNum : num;                   //获取最大值
                }
            }

            //规整化
            for (int r = 0; r < strRow.Length; r++)
            {
                strRow[r] = strRow[r].Trim();                               //去除两端空格
                if (strRow[r].Equals("")) continue;                         //获取到空串则跳过

                String[] strLine = strRow[r].Split(',');
                for (int l = 0; l < strLine.Length; l++)
                {
                    int dataNum = strLine[l].Trim().Equals("") ? 0 : Int32.Parse(strLine[l].Trim());  //转化为数值     
                    dataTmp += ((dataNum>=0 ? " ": "") + dataNum);           //添加到字符串
                    if (l != strLine.Length - 1) dataTmp += ",";            //不是该行最后一个数据
                    dataTmp += SpaceFill(dataNum, maxNum);                  //规整化
                }
                if (r != strRow.Length - 1 && !(r == strRow.Length - 2 && strRow[strRow.Length - 1].Trim().Equals("")))
                    dataTmp += ";\r\n";                                     //对于非最后一行换行显示，若最后一行为空则提前一行进行判断
            }

            return dataTmp;
        }

        //从字符串型数值数组中获取最大的数
        private int getMaxNum(String[] data)
        {
            int max = 0;
            foreach (string str in data)
            {
                String strTmp = str.Trim();
                int tmp = Math.Abs(strTmp.Equals("") ? 0 : Int32.Parse(str.Trim()));  //转化为数值
                max = max > tmp ? max : tmp;                                //记录最大值
            }
            return max;
        }

        //空格填充函数用于实现输出的规格化输出对齐，以最大位数为基准
        String SpaceFill(int m, int n)
        {
            String str = "";

            int a = m, b = n, ia = 0, ib = 0, i = 0;
            while (a >= 10) { a = a / 10; ia++; }
            while (b >= 10) { b = b / 10; ib++; }

            if (ib > ia) ia = ib - ia;				//计算数字m和n的位数之差，以此决定需要输出的空格数
            else ia = ia - ib;

            for (; i < ia; i++) str += " ";         //生成空格填充串

            return str;
        }

        //提取文件中的数据并保存
        private void ExtractionAndSave(String filePath)
        {
            //String filePath = filePath0.Trim(); //去除两端空格
            int i = filePath.LastIndexOf('\\');
            int j = filePath.LastIndexOf('.');


            String name = Path.GetFileNameWithoutExtension(filePath);
            //String name = filePath.Substring(0, filePath.Length - 4);    //获取文件的名称不含后缀

            string CurDir = System.AppDomain.CurrentDomain.BaseDirectory + DateTime.Now.Date.ToString("yyyy_MM_dd") + @"导出\";         //设置当前目录
            if (!System.IO.Directory.Exists(CurDir)) System.IO.Directory.CreateDirectory(CurDir);   //该路径不存在时，在当前文件目录下创建文件夹"导出.."

            try
            {   //不存在该文件时先创建
                System.IO.StreamWriter file1 = new System.IO.StreamWriter(CurDir + name + ".txt", true);
                //System.IO.StreamWriter file1 = new System.IO.StreamWriter(name + ".txt");

                String data = ExtractionData(filePath);                 //提取数据成指定格式
                file1.WriteLine(data);                                  //保存数据到文件

                file1.Close();                                          //关闭文件
                file1.Dispose();                                        //释放对象
                MessageBox.Show("成功导出数据到:“" + file1 + "”!");
            }
            catch (Exception)
            {
                MessageBox.Show("保存提取数据失败");
            }
        }


        //导出到txt
        private void button4_Click(object sender, EventArgs e)
        {
            SaveToFile(FormatEdit());                           //提取编辑界面中的数据保存到txt文件中
            //string files = textBox1.Text;
            //if (files.IndexOf(';') > 0)             //文件
            //{
            //    foreach (string file in files.Split(';'))
            //    {
            //        ExtractionAndSave(file);    //提取并保存数据
            //    }
            //}
            //else if (files.Trim().Equals(""))
            //    MessageBox.Show("请打开要提取信息的XML文件！");
            //else ExtractionAndSave(files);    //提取并保存数据
        }

        //保存数据过程
        private String SaveProcess(String data)
        {
            String filePath = OpendFilesName[curFilesNum - 1];
            if (!System.IO.File.Exists(filePath)) return "请先打开一个关卡资源，再进行操作！";

            System.IO.StreamWriter file1 = new System.IO.StreamWriter(filePath, false);     //文件已覆盖方式添加内容

            file1.Write(data);                                                              //保存数据到文件

            file1.Close();                                                                  //关闭文件
            file1.Dispose();                                                                //释放对象

            return "已保存！";
        }

        //保存数据过程
        private String SaveProcess(String data, String name)
        {
            string CurDir = System.AppDomain.CurrentDomain.BaseDirectory + DateTime.Now.Date.ToString("yyyy_MM_dd") + @"导出\";         //设置当前目录
            if (!System.IO.Directory.Exists(CurDir)) System.IO.Directory.CreateDirectory(CurDir);   //该路径不存在时，在当前文件目录下创建文件夹"导出.."

            //不存在该文件时先创建
            //System.IO.StreamWriter file1 = new System.IO.StreamWriter(CurDir + name + ".txt", true);
            String filePath = CurDir + name + ".txt";
            System.IO.StreamWriter file1 = new System.IO.StreamWriter(filePath, false);   //文件已覆盖方式添加内容

            file1.Write(data);
            //file1.WriteLine(data);                                                        //保存数据到文件

            file1.Close();                                                                  //关闭文件
            file1.Dispose();                                                                //释放对象

            if (OpendFilesName != null) OpendFilesName[curFilesNum - 1] = filePath;         //记录新的文件位置
            else
            {
                OpendFilesName = (filePath + ";").Split(';');
                curFilesNum = 1;
            }

            return filePath;
        }

        //保存数据data到文件
        private void SaveToFile(String data)
        {
            String name = textBox12.Text.Trim();    //保存文件名
            if (name.Equals("（重命名）"))
            {
                MessageBox.Show("请输入要保存文件的名称！");
                return;
            }

            try
            {
                if (checkBox23.Checked) MessageBox.Show(SaveProcess(data));
                else MessageBox.Show("成功导出数据到:“" + SaveProcess(data, name) + "”!");
            }
            catch (Exception)
            {
                MessageBox.Show("保存提取数据失败");
            }
        }

        //静默的保存数据data到文件
        private bool SaveToFileMute(String data)
        {
            String name = textBox12.Text.Trim();    //保存文件名
            if (OpendFilesName == null && name.Equals("（重命名）"))
            {
                textBox12.Text = DateTime.Now.ToLongTimeString().Replace(":",".");          //使用系统时间自动为文件命名
                return SaveToFileMute(data);                                                //保存数据到文件
            }
            else if(OpendFilesName != null)
            {
                name = Path.GetFileNameWithoutExtension(OpendFilesName[curFilesNum-1]);     //文件名
                this.Text = "CandyHouse-关卡编辑" + " - " + name;
                textBox12.Text = name;
            }

            try
            {
                if (checkBox23.Checked) SaveProcess(data);
                else SaveProcess(data, name);
                mutexSaveFinish = true;     //保存完成
                return true;
            }
            catch (Exception)
            {
               return false;
            }
        }

        //提取界面中的数据转化为指定的格式
        private String FormatEdit()
        {
            bool style = isEnglish;         //保存样式类型
            setLanguageStyle(true);         //切换到英文样式

            if (checkBox15.Checked) button8_Click(null, null);                                      //导出数据到图块，导出传送属性

            String data = "";
            if (textBox2.Text.Trim().Equals("")) button8_Click(null, null);                         //图块数据空校验 
            if (textBox7.Text.Trim().Equals("")) textBox7_MouseDoubleClick(null, null);             //根据tileMap数据重新生成 portoals ——不再自动生成传送
            if (textBox4.Text.Trim().Equals("")) textBox4_DoubleClick(null, null);                  //随机种子空值校验
            if (textBox16.Text.Trim().Equals("")) textBox16.Text = "9, 90;  15, 75";                //关卡难度默认值

            //从编辑界面中读取属性数据
            String gameModeName = comboBox1.Text;
            String numberOfColours = textBox3.Text.Trim().Equals("") ? "6" :textBox3.Text;          //水果中类数默认为6
            String portals = textBox7.Text;

            String protocolVersion = comboBox4.Text;
            String randomSeed = textBox4.Text;
            String scoreTargets = textBox5.Text.Trim().Equals("") ? "500 600 800" : textBox5.Text;  //目标分数默认值
            String tileMap = textBox2.Text;

            String ingredientSpawnDensity = textBox8.Text;
            String ingredients = textBox9.Text;
            String moveLimit = textBox6.Text.Trim().Equals("") ? "50" : textBox6.Text;              //默认步数限定50
            String numIngredientsOnScreen = textBox10.Text;
            String ingredientsFruit = textBox15.Text;
            
            String levelDifficulty = textBox16.Text;
            String fruitData = ArrayTostring(this.fruitData, RL[2], RL[3]);                         //将水果数据转化为字符串

            int add = 4;    //添加的新属性

            //转化为要显示的数据格式
            String[] dataTmp = new String[11+add];  //存储各个属性项
            dataTmp[0] = NameFormat(label1.Text) + DataFormat(gameModeName);
            dataTmp[1] = NameFormat(label2.Text) + numberOfColours.Trim();
            dataTmp[2] = NameFormat(label3.Text) + DataFormat2(portals.Trim().Equals("") ? "" : "[[" + portals.Replace(" ", "").Replace("\r\n", "").Replace(".", "],[").Replace(";", "]],[[") + "]]").Replace(",[[]]", "");

            dataTmp[3] = NameFormat(label4.Text) + DataFormat(protocolVersion);
            dataTmp[4] = NameFormat(label5.Text) + randomSeed.Trim();
            dataTmp[5] = NameFormat(label6.Text) + DataFormat2(scoreTargets.Trim().Replace(" ", ","));
            dataTmp[6] = NameFormat(label7.Text) + DataFormat2("[" + tileMap.Replace(" ", "").Replace("\r\n", "").Replace(";", "],[") + "]").Replace(",[]", "").Replace("[]", "").Replace(",]", "");
            
            dataTmp[7 + add] = ingredientSpawnDensity.Trim().Equals("") ? "" : NameFormat(label9.Text) + ingredientSpawnDensity.Trim();
            dataTmp[8 + add] = ingredients.Trim().Equals("") ? "" : NameFormat(label10.Text) + DataFormat2(ingredients.Trim().Replace(" ", ","));
            dataTmp[9 + add] = (comboBox1.SelectedIndex != 1 ? NameFormat("moveLimit:") : NameFormat("timeLimit:")) + moveLimit.Trim();  //@@@@
            dataTmp[10 + add] = numIngredientsOnScreen.Trim().Equals("") ? "" : NameFormat(label11.Text) + numIngredientsOnScreen.Trim();
            dataTmp[6 + add] = NameFormat("switchs:") + "[" +getSwitch() +"]";    //控制开关状态保存


            dataTmp[7] = NameFormat(label14.Text) + DataFormat2("[" + ingredientsFruit.Replace(" ", "").Replace("\r\n", "").Replace(";", "],[") + "]").Replace(",[]", "").Replace("[]", "").Replace("[,]", ""); //新增属性，收集水果
            dataTmp[8] = NameFormat(label17.Text) + DataFormat2("[" + levelDifficulty.Replace(" ", "").Replace("\r\n", "").Replace(";", "],[") + "]").Replace(",[]", "").Replace("[]", "").Replace("[,]", "");  //新增属性，关卡难度控制
            dataTmp[9] = NameFormat("fruitData:") + DataFormat2("[" + fruitData.Replace(" ", "").Replace("\r\n", "").Replace(";", "],[") + "]").Replace(",[]", "").Replace("[]", "").Replace(",]", "");         //保存水果类型数据
            


            //合并所有项
            data += "{";
            for (int i = 0; i < dataTmp.Length; i++)
            {
                if (i < dataTmp.Length - 2) data += dataTmp[i].Equals("") ? "" : (dataTmp[i] + ",");
                else if (i == dataTmp.Length - 2) data += dataTmp[i].Equals("") ? "" : (dataTmp[i] + (dataTmp[i + 1].Equals("") ? "" : ","));
                else data += dataTmp[i];
            }
            data += "}";

            setLanguageStyle(style);        //切换回原样式
            return data;
        }

        //获取界面中的控制开关状态
        private String getSwitch()
        {
            String str = "";
            CheckBox[] switchs = 
            {
                checkBox16, checkBox17, checkBox18, checkBox19, checkBox20, checkBox21,     //6种水果选择状态
                checkBox12, checkBox22, checkBox30, checkBox31                              //初始固定水果、初始固定道具
            };

            foreach (CheckBox check in switchs) str += ((str.Equals("") ? "" : ",") + (check.Checked ? "1" : "0"));          //拼接开关控制状态为字符串，1选中、0未选中

            return str;
        }

        //根据给定的字符串，设置开关的选中状态
        private void setSwitch(int[] state)
        {
            if (state == null) return;          //没有有效数据则返回

            try
            {
                CheckBox[] switchs = 
                {
                    checkBox16, checkBox17, checkBox18, checkBox19, checkBox20, checkBox21,     //6种水果选择状态
                    checkBox12, checkBox22, checkBox30, checkBox31                              //初始固定水果、初始固定道具
                };

                for (int i = 0; i < switchs.Length; i++)                                        //设置开关选中状态
                    switchs[i].Checked = state[i] == 1 ? true : false;
            }
            catch (Exception ex)
            {}
        }

        /// <summary>
        /// 将2维整形数组转化为用，；分隔的字符串
        /// </summary>
        private String ArrayTostring(int[,] data, int R, int L)
        {
            String str = "";

            for(int i=0; i<R; i++)
            {
                for(int j=0; j<L; j++)
                {
                    str += data[i, j];
                    if (j != L - 1) str += ",";
                }
                if (i != R - 1) str += ";";
            }

            return str;
        }

        //属性项名称转化样式，如：gameModeName -> "gameModeName":
        private String NameFormat(String name)
        {
            return "\"" + name.Trim().Replace(":", "\":");
        }

        //属性项数据转化样式，如：Classic moves -> "Classic moves"
        private String DataFormat(String data)
        {
            return "\"" + data.Trim() + "\"";
        }

        //属性项数据转化样式，如：Classic moves -> [Classic moves]
        private String DataFormat2(String data)
        {
            return "[" + data.Trim() + "]";
        }

        //放下, 另外需设置对应控件的 AllowDrop = true; 
        //获取的文件名形如 "d:\1.txt;d:\2.txt;"
        String dragDrop(TextBox textBox1, DragEventArgs e)
        {
            String filesName = "";
            Array file = (System.Array)e.Data.GetData(DataFormats.FileDrop);//将拖来的数据转化为数组存储

            int len = file.Length;
            for (int i = 0; i < len; i++)
                filesName += (file.GetValue(i).ToString() + ";");

            textBox1.Text = filesName;
            return filesName;
            //int len = file.Length;
            //for (int i = 0; i < len; i++)
            //    if (textBox1.Text.Equals("")) textBox1.Text = file.GetValue(i).ToString();
            //    else textBox1.Text += ";" + file.GetValue(i).ToString();
        }

        //放下第一个文件, 另外需设置对应控件的 AllowDrop = true;
        private void dragDrop1(TextBox textBox1, DragEventArgs e)
        {
            Array file = (System.Array)e.Data.GetData(DataFormats.FileDrop);//将拖来的数据转化为数组存储

            textBox1.Text = "";
            int len = file.Length;
            for (int i = 0; i < len; i++)
            {
                if (textBox1.Text.Equals("")) textBox1.Text = file.GetValue(i).ToString();
                else textBox1.Text += ";" + file.GetValue(i).ToString();
                break;
            }
        }

        //拖进
        private void dragEnter(DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))    //判断拖来的是否是文件
                e.Effect = DragDropEffects.Link;                //是则将拖动源中的数据连接到控件
            else e.Effect = DragDropEffects.None;
        }

        //放下文件
        private void textBox1_DragDrop(object sender, DragEventArgs e)
        {
            String fileNameTmp = textBox1.Text.Trim(); //暂存文件名

            //String tmp = (dragDrop(textBox1, e));
            OpendFilesName = (dragDrop(textBox1, e)).Split(';');  //获取所有添加的文件名
            curFilesNum = 1;                              //第一项选为当前文件项

            refrashEditor();                               //刷新编辑器的显示界面

            //dragDrop1(textBox1, e);                    //放下第一个文件
            //String filePath = textBox1.Text.Trim();    //获取文件完整路径

            //String name = Path.GetFileNameWithoutExtension(filePath);           //文件名
            //this.Text = "CandyHouse-关卡编辑" + " - " + name;
            //textBox12.Text = name;

            ////文件类型校验
            //String nameExtension = Path.GetExtension(filePath);                 //拓展名

            //if (nameExtension.ToUpper().Equals(".XML"))
            //{
            //    //TileMap部分
            //    textBox11.Text = "";
            //    textBox2.Text = ExtractionData2(textBox1.Text.Trim());          //预览提取的XML数据
            //}
            //else if (nameExtension.ToUpper().Equals(".TXT"))
            //{
            //    textBox11.Text = "";
            //    textBox7.Text = ExtraTXT_portals(textBox1.Text.Trim());         //portals属性部分预览
            //    textBox2.Text = ExtraTXT_tileMap(textBox1.Text.Trim());         //TileMap属性部分预览

            //    ExtraTXT_Orthers(textBox1.Text.Trim());                         //显示其他的属性
            //}
            //else
            //{
            //    MessageBox.Show("暂不支持“*" + nameExtension + "”类型的文件！");
            //    textBox1.Text = fileNameTmp;           //恢复文件名
            //}
        }

        //刷新编辑器的显示
        private void refrashEditor()
        {
            try
            {
                if (OpendFilesName == null) MessageBox.Show("请打开一个现有，关卡数据文件！");
                else
                {
                    //OpendFilesName中含有1到OpendFilesName.Length - 1个有效文件
                    int OpenFilesNum = OpendFilesName.Length - 1;
                    if (curFilesNum > OpenFilesNum) curFilesNum = 1;
                    else if (curFilesNum < 1) curFilesNum = OpenFilesNum;

                    refrashEditor(OpendFilesName[curFilesNum - 1]);
                    textBox13.Text = curFilesNum.ToString();
                    label16.Text = "/ " + OpenFilesNum + " 项";

                    if (checkBox13.Checked) button9_Click(null, null);              //锁定从tileMap导入数据到编辑器视图中

                    //打开多个文件时显示该组控件
                    if (OpenFilesNum >= 2) groupBox5.Visible = true;
                    else groupBox5.Visible = false;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("更新界面显示出错，请检查文件\n“" + OpendFilesName + "”\n格式是否正常");
            }
        }

        //刷新编辑器的显示
        private void refrashEditor(String filePath)
        {
            fruitDataInit();                           //跳转下一关前先初始化水果数据
            //CA = new Point[RL[2], RL[3]];              //初始化传送接收数组
            CA_num = new int[RL[2], RL[3], 2];         //传送接收标号
            CA_count = 0;                              //计数变量清零

            String fileNameTmp = textBox1.Text.Trim(); //暂存文件名

            String name = Path.GetFileNameWithoutExtension(filePath);           //文件名
            this.Text = "(农场版)消除大师-关卡编辑" + " - " + name;
            textBox12.Text = name;

            //文件类型校验
            String nameExtension = Path.GetExtension(filePath);                 //拓展名

            if (nameExtension.ToUpper().Equals(".XML"))
            {
                //TileMap部分
                textBox11.Text = "";
                textBox2.Text = ExtractionData2(textBox1.Text.Trim());          //预览提取的XML数据
            }
            else if (nameExtension.ToUpper().Equals(".TXT"))
            {
                textBox11.Text = "";
                ExtraTXT_Orthers(filePath);                                     //显示其他的属性

                textBox7.Text = ExtraTXT_portals(filePath);                     //portals属性部分预览
                textBox2.Text = ExtraTXT_tileMap(filePath);                     //TileMap属性部分预览

                textBox15_DoubleClick(null, null);                              //更新收集水果数据到收集水果栏
            }
            else
            {
                MessageBox.Show("暂不支持“*" + nameExtension + "”类型的文件！");
                textBox1.Text = fileNameTmp;           //恢复文件名
            }
        }

        //从portals属性串中提取属性值，生成数组， 输入：portalsStr = "1, 0 . 1, 2 ;6, 0 . 6, 2 ;2, 2 . 2, 4"
        private int[][] getPortals(String portalsStr)
        {
            if (portalsStr.Trim().Equals("")) return null;  //如果给出为空串，则返回空值

            String[] tmp1 = portalsStr.Replace(".", ",").Replace("\r\n", "").Replace(" ", "").Split(';');   //分割为传送接收项 1, 0 , 1, 2
            int[][] data = new int[tmp1.Length][];

            for (int i = 0; i < tmp1.Length; i++)
            {
                String[] tmp2 = tmp1[i].Split(',');         //继续分割为 "1"、 "0"、 "1"、 "2"
                data[i] = new int[tmp2.Length];

                for (int j = 0; j < tmp2.Length; j++)       //串转化为数值到数组中
                    data[i][j] = Int32.Parse(tmp2[j]);
            }
            return data;
        }

        //文件拖进
        private void textBox1_DragEnter(object sender, DragEventArgs e)
        {
            dragEnter(e);
        }

        //从XML导入TileMap数据
        private void button6_Click(object sender, EventArgs e)
        {
            //获取 XML文件名 到文本框中
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.InitialDirectory = System.AppDomain.CurrentDomain.BaseDirectory; //使用当前目录作为初始目录
            dialog.Filter = "XML文件(*.XML)|*.XML";             //仅打开XML
            dialog.Multiselect = false;                         //单个文件
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                textBox11.Text = dialog.FileName;               //显示选择的文件
                textBox2.Text = ExtractionData2(textBox11.Text.Trim());             //预览提取的XML数据
            }
        }

        //从txt导入TileMap数据
        private void button5_Click(object sender, EventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.InitialDirectory = System.AppDomain.CurrentDomain.BaseDirectory; //使用当前目录作为初始目录
            dialog.Filter = "TXT文件(*.TXT)|*.TXT";             //仅打开TXT
            dialog.Multiselect = false;                         //单个文件
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                textBox11.Text = dialog.FileName;               //显示选择的文件

                //textBox2.Text = ExtractionData2(textBox11.Text.Trim());           //预览提取的XML数据
                textBox2.Text = ExtraTXT_tileMap(textBox11.Text.Trim());             //预览提取的TXT数据
            }
        }

        //文件拖进
        private void textBox11_DragEnter(object sender, DragEventArgs e)
        {
            dragEnter(e);
        }

        //文件放下
        private void textBox11_DragDrop(object sender, DragEventArgs e)
        {
            String fileNameTmp = textBox11.Text.Trim(); //暂存文件名

            dragDrop1(textBox11, e);                    //放下一个文件
            String filePath = textBox11.Text.Trim();    //获取文件完整路径

            String name = Path.GetFileNameWithoutExtension(filePath);           //文件名

            //文件类型校验
            String nameExtension = Path.GetExtension(filePath);                 //拓展名

            if (nameExtension.ToUpper().Equals(".XML"))
                textBox2.Text = ExtractionData2(textBox11.Text.Trim());         //预览提取的XML数据
            else if (nameExtension.ToUpper().Equals(".TXT"))
                textBox2.Text = ExtraTXT_tileMap(textBox11.Text.Trim());                //预览提取的TXT数据
            else
            {
                MessageBox.Show("暂不支持“*" + nameExtension + "”类型的文件！");
                textBox11.Text = fileNameTmp;           //恢复文件名
            }

        }

        private void button7_Click(object sender, EventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.InitialDirectory = System.AppDomain.CurrentDomain.BaseDirectory; //使用当前目录作为初始目录
            dialog.Filter = "TXT文件(*.TXT)|*.TXT";             //仅打开TXT
            dialog.Multiselect = true;                          //多个文件

            if (dialog.ShowDialog() == DialogResult.OK)
            {
                String filesName = "";
                foreach (String str in dialog.FileNames) filesName += str + ";";
                textBox1.Text = filesName;

                OpendFilesName = filesName.Split(';');
                curFilesNum = 1;                              //第一项选为当前文件项

                refrashEditor();                               //刷新编辑器的显示界面
            }
        }

        //跳转到指定文件项
        private void button1_Click_1(object sender, EventArgs e)
        {
            try
            {
                int pos = Int32.Parse(textBox13.Text.Trim());
                if (pos == curFilesNum)
                {
                    curFilesNum++;
                    refrashEditor();             //刷新显示指定项
                }
                else
                {
                    curFilesNum = pos;
                    refrashEditor();             //刷新显示指定项
                }
            }
            catch (Exception ex )
            {
                return;
            }
        }

        //选择游戏模式，显示对应的属性控件
        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            bool[] set1 = { false, false, true, false, false };
            bool[] set2 = { false, false, true, false, false }; 
            bool[] set3 = { true, true, true, true, false }; 
            bool[] set4 = { false, false, true, false, true }; 
            bool[] set5 = { false, false, true, false, false };
            bool[][] Setting = { set1, set2, set3, set4, set5 };    //对应游戏模式的控件设置

            setEnable(Setting[comboBox1.SelectedIndex]);            //根据选中项设置可用性

            radioButton1.Checked = true;                            //选中
            UI_AutoVisible();                                       //设置控件是否可见


            ////中文模式时，更新显示标签，用于计时、或计步
            //if (!isEnglish) label8.Text = "moveLimit:";
            //else
            //{
            //    if (comboBox1.SelectedIndex == 1)                   //计时模式
            //        label8.Text = "总时间:";
            //    else label8.Text = "总步数:";                       //其他模式计步
            //}
        }

        //设置这几个文本框是否可用
        private void setEnable(bool[] b)
        {
            TextBox[] textBox = { textBox8, textBox9, textBox6, textBox10, textBox15 };
            for (int i = 0; i < textBox.Length; i++)
            {
                textBox[i].Enabled = b[i];              //设置对应文本框是否可用
                if (!b[i]) textBox[i].Text = "";        //文本框不可用，则清空其文本
            }
        }

        private void label3_Click(object sender, EventArgs e)
        {
            textBox7.Text = " 0, 0 . 0, 2 ;\r\n 8, 0 . 8, 2 ;\r\n 0, 2 . 0, 4 ;\r\n 8, 4 . 8, 6 ;\r\n 0, 4 . 0, 6 ;\r\n 8, 2 . 8, 4 ";
        }

        private void label7_Click(object sender, EventArgs e)
        {
            textBox2.Text = " 0,  0,  18, 18, 18, 18, 18, 0,  0 ;\r\n 0,  0,  2,  2,  2,  2,  2,  0,  0 ;\r\n 0,  0,  2,  2,  2,  2,  2,  0,  0 ;" +
                "\r\n 0,  0,  2,  2,  2,  2,  2,  0,  0 ;\r\n 0,  0,  2,  2,  2,  2,  2,  0,  0 ;\r\n 0,  0,  2,  2,  2,  2,  2,  0,  0 ;\r\n 0,  0,  2,  2,  2,  2,  2,  0,  0 ;" +
                "\r\n 0,  0,  2,  2,  2,  2,  2,  0,  0 ;\r\n 0,  0,  0,  0,  0,  0,  0,  0,  0 ";
        }

        private void 刷新ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if(SaveToFileMute(FormatEdit()))                        //静默的保存当前编辑
                refrashEditor(OpendFilesName[curFilesNum - 1]);     //使用刚保存的文件刷新显示当前编辑器
        }

        //仅允许输入数值
        private void onlyNumberInput0(object sender, KeyPressEventArgs e)
        {
            int key = Convert.ToInt32(e.KeyChar);
            if (!(48 <= key && key <= 58 || key == 8)) //数字、 Backspace
            {
                label13.Text = "keyChar:" + key.ToString();
                e.Handled = true;
            }
            else label13.Text = "";
        }

        //仅允许输入数值 和 空格
        private void onlyNumberInput(object sender, KeyPressEventArgs e)
        {
            int key = Convert.ToInt32(e.KeyChar);
            if (!(48 <= key && key <= 58 || key == 32 || key == 8)) //数字、 ' '、 Backspace
            {
                label13.Text = "keyChar:" + key.ToString();
                e.Handled = true;
            }
            else label13.Text = "";
        }

        //仅允许输入数值
        private void onlyNumberCharInput1(object sender, KeyPressEventArgs e)
        {
            int key = Convert.ToInt32(e.KeyChar);
            if (!(48 <= key && key <= 58 || key == 44 || key == 46 || key == 59 || key == 32 || key == 8 || key == 13)) //数字、 ','、 '.'、 ';'、  ' '、 Backspace、Enter
            {
                label13.Text = "keyChar:" + key.ToString();
                e.Handled = true;
            }
            else label13.Text = "";
        }

        //仅允许输入数值
        private void onlyNumberCharInput2(object sender, KeyPressEventArgs e)
        {
            int key = Convert.ToInt32(e.KeyChar);
            if (!(48 <= key && key <= 58 || key == 44 || key == 59 || key == 32 || key == 8 || key == 13)) //数字、 ','、 '.'、 ';'、  ' '、 Backspace、Enter
            {
                label13.Text = "keyChar:" + key.ToString();
                e.Handled = true;
            }
            else label13.Text = "";
        }

        //仅允许输入数值
        private void onlyNumberCharInput3(object sender, KeyPressEventArgs e)
        {
            int key = Convert.ToInt32(e.KeyChar);
            if (!(48 <= key && key <= 58 || key == 44 || key == 59 || key == 32 || key == 8)) //数字、 ','、 ';'、  ' '、 Backspace
            {
                label13.Text = "keyChar:" + key.ToString();
                e.Handled = true;
            }
            else label13.Text = "";
        }

        private void textBox14_TextChanged(object sender, EventArgs e)
        {
            if (mutex == false) return;     //如果check正被使用则返回

            mutex = false;

            String str = textBox14.Text.Trim();

            int tmp = 0;
            try { tmp = Int32.Parse(str);}
            catch (Exception ex){}
            int data = str.Equals("") ? 0 : tmp;

            CheckBox[] check = { checkBox2, checkBox3, checkBox4, checkBox5, checkBox6, checkBox7, checkBox8, checkBox11, checkBox9, checkBox10 };
            int[] num = { 2, 4, 8, 16, 32, 128, 512, 1024, 2048, 4096 };

            for (int i = 0; i < check.Length; i++) check[i].Checked = false;    //所有控件清除选择

            //根据组合数据选择对应的属性
            checkBox1.Checked = data != 0 ? true : false;
            for (int i = 0; i < check.Length; i++)
            {
                if (num[i] == 32)
                {
                    if ((data & num[i]) != 0 && (data & 2 * num[i]) != 0) check[i].Checked = true;
                }
                else if((data & num[i]) != 0) check[i].Checked = true;
            }

            mutex = true;
        }


        //文本框文本选中
        private int selectionStart = -1;
        private int selectionLength = 0;
        private void SelectText(TextBox textBox, int start, int len)
        {
            if (start < 0) return;              //选中文本起点位置校验

            textBox.Focus();                    //文本框获得焦点

            //设置文本选中效果
            textBox.SelectionStart = start;     //设置起始位置 
            textBox.SelectionLength = len;      //设置长度

            textBox.ScrollToCaret();            //滚动到对应位置
        }

        //双击添加选中文本到textBox14进行属性值解析
        private void textBox2_DoubleClick(object sender, EventArgs e)
        {
            try 
            {
                selectionStart = textBox2.SelectionStart;
                selectionLength = textBox2.SelectionLength;

                textBox14.Text = textBox2.SelectedText.Replace(",", "").Replace(";", "").Trim();
            }
            catch(Exception ex)
            {
                MessageBox.Show("双击 tileMap 属性文本中的数值部分");
            }
        }

        //属性解析值变动
        private void CheckedChanged(object sender, EventArgs e)
        {
            SelectText(textBox2, selectionStart, selectionLength);          //保持tileMap中的数据选定

            if (mutex == false) return;     //如果check正被使用则返回

            mutex = false;

            CheckBox[] check = { checkBox2, checkBox3, checkBox4, checkBox5, checkBox6, checkBox7, checkBox8, checkBox11, checkBox9, checkBox10 };
            int[] num = { 2, 4, 8, 16, 32, 128, 512, 1024, 2048, 4096 };

            //生成属性值
            int data = 0;
            for (int i = 0; i < check.Length; i++)
            {
                if (num[i] == 32)
                {
                    if (check[i].Checked) data += (32 + 64);
                }
                else if (check[i].Checked) data += num[i];
            }

            textBox14.Text = data.ToString();   //显示到文本框

            mutex = true;
        }

        //如果check1选中则check2是否可用由enable限定
        private void constract(CheckBox check1, CheckBox check2, bool enable)
        {
            check2.Checked = false;          //选中状态清除

            if (check1.Checked) check2.Enabled = enable;    //不可用
            else check2.Enabled = !enable;                  //可用
        }

        private void checkBox6_CheckedChanged(object sender, EventArgs e)
        {
            constract(checkBox6, checkBox2, false);    //石块选中则水果属性不可用

            CheckedChanged(sender, e);
        }

        private void checkBox2_CheckedChanged(object sender, EventArgs e)
        {
            constract(checkBox2, checkBox6, false);    //水果选中则石块属性不可用
            constract(checkBox2, checkBox7, true);     //水果选中则可以锁定
            constract(checkBox2, checkBox5, true);     //有水果的位置可以在水果消去后生成

            CheckedChanged(sender, e);
        }

        private void checkBox3_CheckedChanged(object sender, EventArgs e)
        {
            constract(checkBox3, checkBox4, false);    //冰选中则两层冰不可用

            CheckedChanged(sender, e);
        }

        private void checkBox4_CheckedChanged(object sender, EventArgs e)
        {
            constract(checkBox4, checkBox3, false);    //两层冰选中则冰不可用

            CheckedChanged(sender, e);
        }

        //允许复制 和 粘贴
        private void Copy_Paste(object sender, KeyPressEventArgs e)
        {
            int key = Convert.ToInt32(e.KeyChar);
            if (key == 3 || key == 22) //Ctrl+C、 Ctrl+V
            {
                e.Handled = false;
                label13.Text = "";
            }
        }

        private void textBox7_KeyPress(object sender, KeyPressEventArgs e)
        {
            onlyNumberCharInput1(sender, e);
            Copy_Paste(sender, e);
        }

        private void textBox2_KeyPress(object sender, KeyPressEventArgs e)
        {
            onlyNumberCharInput2(sender, e);
            Copy_Paste(sender, e);
        }

        private void textBox14_KeyPress(object sender, KeyPressEventArgs e)
        {
            onlyNumberInput(sender, e);
            Copy_Paste(sender, e);
        }

        private void textBox14_DoubleClick(object sender, EventArgs e)
        {
            SelectText(textBox2, selectionStart, selectionLength);          //保持tileMap中的数据选定

            String str = textBox14.Text.Trim() + ", ";
            if (selectionStart >= 0 && str.Length > 0) textBox2.SelectedText = str;
            selectionLength = str.Length;

            SelectText(textBox2, selectionStart, selectionLength);          //重新选中新的文本
        }

        //更新随机种子
        private void textBox4_DoubleClick(object sender, EventArgs e)
        {
            Random rnd = new Random();
            textBox4.Text = rnd.Next(1088126).ToString();
        }

        /// <summary>
        /// 根据TileMap数据，生成portals数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBox7_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            int[][] tileMap = getTwoDimentionData(textBox2.Text);               //读取二维数组数据
            String portals = getPortals(tileMap);                               //从tileMap中提取portals数据
            textBox7.Text = portals;                                            //显示到文本框
        }

        /// <summary>
        /// 从字符串str中读取数据，生产二维数组数据,
        /// 串str的表示格式形如： 1，2，3，4；5，6，7，8；9，10，11，12
        /// </summary>
        /// <returns></returns>
        public int[][] getTwoDimentionData(String str)
        {
            String tileMapStr = str.Replace(" ", "").Replace("\r\n", "");       //去除空格和换行符
            if (tileMapStr.Equals("")) return null;                             //空串返回数据为空

            //行分割
            String[] tileMapStr1 = tileMapStr.Split(';');
            int[][] tileMapData = new int[tileMapStr1.Length][];

            int maxlen = 0;
            for (int i = 0; i < tileMapStr1.Length; i++)
            {
                //每一行中的数据项分割
                String[] tileMapStr2 = tileMapStr1[i].Split(',');
                tileMapData[i] = new int[tileMapStr2.Length];

                for (int j = 0; j < tileMapStr2.Length; j++)
                {
                    try { tileMapData[i][j] = Int32.Parse(tileMapStr2[j]); }    //读取数据项到数组中
                    catch (Exception e) { tileMapData[i][j] = 0; }
                }
                if (maxlen < tileMapStr2.Length) maxlen = tileMapStr2.Length;   //记录所有行的最大列数
            }

            //将数据转换为矩形数据存储
            int[][] data = new int[tileMapData.Length][];
            for (int i = 0; i < tileMapData.Length; i++)
            {
                data[i] = new int[maxlen];
                for (int j = 0; j < tileMapData.Length; j++)
                    data[i][j] = tileMapData[i][j];
            }

            return data;
        }

        /// <summary>
        /// 根据二维数组data中的数据生成portals数据串。
        /// 生成原理：
        /// 获取每一列数据中连续相邻的数据0（上方的位置，下方的位置）为一个portoals项
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public String getPortals(int[][] data)
        {
            String str = "";
            if (data == null) return str;

            for (int j = 0; j < data[0].Length; j++)        //对于每一列数据
            {
                int pre =  -1;                              //pre记录非0数据的行位置
                for (int i = 0; i < data.Length; i++)
                {
                    if (data[i][j] != 0)
                    {   //(若存在前一个非0项 且 与其不相邻)，则构建portoals项，前一个非0位置指向当前非0位置
                        if (pre != -1 && pre + 1 != i)
                        {
                            str += ((str.Equals("") ? "" : ";\r\n") + j + "," + pre + "." + j + "," + i);

                            tileMapData[pre, j] |= 2048;    //校验传送属性到数据块中
                            tileMapData[i, j] |= 4096;      //校验接收属性到数据块中
                        }

                        pre = i;                            //记录非0项位置
                    }
                }
            }
            return str;
        }


        /// <summary>
        /// 重新绘制pictureBox1界面中的内容
        /// </summary>
        private void refreashpictureBox1()
        {
            //g.DrawImage(XML_Reader.Properties.Resources.background, 0, 0);  //使用背景图像重绘界面

            drawQipan(RL[0], RL[1], toolsRect.X, toolsRect.Y, width);       //绘制工具栏
            drawTools();

            drawQipan(RL[2], RL[3], tileMapRect.X, tileMapRect.Y, width);   //绘制tileMap
            drawTileMap();

            mutexLoadFinish = true;
        }

        /// <summary>
        /// 在tools区域,绘制工具块
        /// </summary>
        private void drawTools()
        {
            for(int i = 0; i<RL[0]; i++)
                for (int j = 0; j < RL[1]; j++)
                {
                    eraserTool(i, j);               //用背景擦除该工具块
                    drawTool(i, j, toolsPic[i, j]); //重新绘制

                    if (i == 1 && 0 <= j && j <= 5)                         //对应水果未选中
                        if (!fruitSelect[j]) drawTool(i, j, unSelcet);      //在该水果上绘制斜杠
                }
        }

        /// <summary>
        /// 在tools区域坐标(x行,y列)处,绘制图像pic,
        /// 行列起点0，绘制块大小为width
        /// </summary>
        private void drawTool(int x, int y, Image pic)
        {
            Point p = new Point(toolsRect.X + y * width, toolsRect.Y + x * width);  //行列位置转化为像素位置
            g.DrawImage(pic, p.X, p.Y, width, width);       //在对应位置绘制图像
        }

        /// <summary>
        /// 绘制整张tileMap
        /// </summary>
        private void drawTileMap()
        {
            for(int i = 0; i<RL[2]; i++)
                for (int j = 0; j < RL[3]; j++)
                {
                    drawTile(i, j, tileMapData[i, j]);      //根据tileMap位置处的数据，在对应位置处绘制图块
                }
        }

        /// <summary>
        /// 在TileMap区域坐标(x行,y列)处,
        /// 根据给定的data数据绘制tile块
        /// </summary>
        private void drawTile(int x, int y, int data)
        {
            eraserTile(x, y);                                               //先擦除当前块内容
            if (data == 0) return;                                          //若为空块则退出绘制
            else drawTile(x, y, toolsPic[0, 0]);                            //重绘存在块

            //绘制属性块
            for (int i = 0; i < RL[0]; i++)
            {
                if (i == 1) continue;                                       //跳过水果行的绘制
                if (i == 2) continue;                                       //跳过第3行的绘制

                for (int j = 0; j < RL[1]; j++)
                {
                    if ((i == 0 && j == 0) || (i == 0 && j == 4)) continue; //跳过存在块 和 锁定块的绘制
                    if ((i == 0 && j == RL[1] - 1) || (i == 1 && j == RL[1] - 1)) continue;     //跳过传送块 和 接收块的绘制

                    bool draw = false;
                    if (i == 0 && j == 3) draw = (data & 32) != 0 && (data & 64) != 0;    //石块为32和64的组合，故需特殊处理
                    else draw = (i == 0 && (data & toolsData[i, j]) != 0);  //包含其他工具块

                    if (draw) drawTile(x, y, toolsPic[i, j]);               //绘制对应的属性块
                }
            }

            //绘制水果
            if ((data & 2) != 0)                                                    //若存在水果属性
            {
                if (fruitData[x, y] / 10 == 0)
                {
                    if (fruitData[x, y] == -1 || fruitData[x, y] >= 6 || !fruitSelect[fruitData[x, y]])  //未指定水果类型、无该水果类型、水果不可用 则随机生成
                    {
                        fruitData[x, y] = (int)Math.Floor(rnd.NextDouble() * numOfFruit);
                        fruitData[x, y] = getFruitType(fruitData[x, y]);                
                    }

                    drawTile(x, y, toolsPic[1, fruitData[x, y]]);                       //绘制对应的水果
                }
                else if (fruitData[x, y] / 10 == 4)                                 //绘制水桶、帽子、太阳 这3个块
                {
                    drawTile(x, y, toolsPic[2, fruitData[x, y] % 10]); 
                }
                else if (fruitData[x, y] / 10 == 1)                                 //绘制光圈水果
                {
                    drawTile(x, y, targeFruit[0, fruitData[x, y] % 10]);
                }
                else if (fruitData[x, y] / 10 == 2 || fruitData[x, y] / 10 == 3)    //绘制标签水果   
                {
                    drawTile(x, y, toolsPic[1, fruitData[x, y] % 10]);                          //绘制水果
                    drawTile(x, y, targeFruit[fruitData[x, y] / 10 -1, fruitData[x, y] % 10]);  //绘制标签
                }
            }

            if ((data & toolsData[0, 4]) != 0) drawTile(x, y, toolsPic[0, 4]);      //重绘锁定块

            if ((data & 16) != 0) drawTileShrink(x, y, toolsPic[2, 6]);      //绘制birth属性

            //传送接收属性绘制
            if (checkBox14.Checked)
            {
                int num;
                if ((data & toolsData[0, RL[1] - 1]) != 0)
                {
                    num = CA_num[x, y, 0];
                    if (num == 0) data &= (~toolsData[0, RL[1] - 1]);               //去除传送属性
                    else drawNumber(x, y, num, true);                               //绘制传送属性
                }
                if ((data & toolsData[1, RL[1] - 1]) != 0)
                {
                    num = CA_num[x, y, 1];
                    if (num == 0) data &= (~toolsData[1, RL[1] - 1]);               //去除接收属性
                    else drawNumber(x, y, num, false);                              //绘制接收属性
                }
            }
        }

        /// <summary>
        /// 在TileMap区域坐标(x行,y列)处,绘制图像pic,
        /// 行列起点0，绘制块大小为width
        /// </summary>
        private void drawTile(int x, int y, Image pic)
        {
            Point p = new Point(tileMapRect.X + y * width, tileMapRect.Y + x * width);  //行列位置转化为像素位置
            g.DrawImage(pic, p.X+1, p.Y+1, width-1, width-1);       //在对应位置绘制图像，偏移减小一个像素避开棋盘线
        }

        private void drawTileShrink(int x, int y, Image pic)
        {
            Point p = new Point(tileMapRect.X + y * width, tileMapRect.Y + x * width);          //行列位置转化为像素位置
            g.DrawImage(pic, p.X + width / 2, p.Y + width / 2, width / 2 - 1, width / 2 - 1);   //在对应位置绘制图像，偏移减小一个像素避开棋盘线
        }

        /// <summary>
        /// 在TileMap区域坐标(x行,y列)处,绘制数值num, C标识是否为传送绘制
        /// 行列起点0，绘制块大小为width
        /// </summary>
        private void drawNumber(int x, int y, int num, bool C)
        {
            Font drawFont = new Font("Arial", 11);
            SolidBrush drawBrush = new SolidBrush(Color.Blue);
            int offY = C ? 15 : 0;                                                      //传送属性绘制到块底端，接收属性在顶端绘制
            Point p = new Point(tileMapRect.X + y * width, tileMapRect.Y + x * width + offY);  //行列位置转化为像素位置
            g.DrawString((C ? "C" : "A") + num, drawFont, drawBrush, p);                //绘制对应的字符串
        }

        /// <summary>
        /// 从指定像素坐标(offX, offY)处开始按width大小绘制图像pic
        /// </summary>
        private void drawTile(Image pic, int offX, int offY, int width)
        {
            g.DrawImage(pic, offX, offY, width, width);  //绘制tileMap块
        }


        /// <summary>
        /// 擦除rect区域中坐标(x行,y列)处的图像
        /// </summary>
        private void eraserTool(int x, int y, Rectangle rect)
        {
            Image background = XML_Reader.Properties.Resources.background;      //背景图像的宽度
            double reSize = background.Width / pictureBox1.Width;               //计算背景的缩放比例

            Point p = new Point(rect.X + y * width + 1, rect.Y + x * width + 1);  //行列位置转化为像素位置，不包含棋盘线的1个像素
            Rectangle destRect = new Rectangle(p, new Size(width - 1, width - 1));  //绘制目标区域

            Point p2 = new Point((int)(p.X * reSize), (int)(p.Y * reSize));
            Size s2 = new Size((int)(width * reSize), (int)(width * reSize));
            Rectangle srcRect = new Rectangle(p2, s2);                          //绘制图像源区域

            g.DrawImage(background, destRect, srcRect, GraphicsUnit.Pixel);     //使用背景图像重绘目标区域
            //g.DrawImage(pic, p.X, p.Y, width, width);       //在对应位置绘制图像
        }

        /// <summary>
        /// 擦除tileMap区域中坐标(x行,y列)处的图像
        /// </summary>
        private void eraserTile(int x, int y)
        {
            eraserTool(x, y, tileMapRect);
        }

        //擦除工具栏坐标处的图形
        private void eraserTool(int x, int y)
        {
            eraserTool(x, y, toolsRect);
        }

        /// <summary>
        /// 绘制棋盘格,M行N列,绘制像素起点(offX, offY),方格宽度width
        /// </summary>
        private void drawQipan(int M, int N, int offX, int offY, int width)
        {
            if (pen1 != null)
            {
                pen1.Width = 2;
                g.DrawRectangle(pen1, offX, offY, width * N + 1, width * M + 1);         //绘制外边框，附加1个像素

                pen1.Width = 1;
                for (int i = 1; i <= M - 1; i++)                                         //绘制行
                    g.DrawLine(pen1, offX, width * i + offY, offX + width * N, width * i + offY);
                for (int i = 1; i <= N - 1; i++)                                         //绘制列
                    g.DrawLine(pen1, offX + width * i, offY, offX + width * i, width * M + offY);
            }
        }

        /// <summary>
        /// 界面初始化，初始化界面设置相关的数据
        /// </summary>
        private void Form1_Load(object sender, EventArgs e)
        {
            int[] tmp = { 3, 7, 9, 9 };                          //行数和列数初始化，前两项为tools行列数，后两项为tileMap的行列数
            RL = tmp;

            g = pictureBox1.CreateGraphics();                   //在对象图片框中创建一个Graphics对象用于绘图
            pen1 = new Pen(Color.Black, 2);                     //创建画笔，用于绘制方格

            border = 3;                                         //设置边距
            width = (int)(pictureBox1.Width - 2 * border) / 9;  //设置方格宽度自适应图片框
             
            
            //初始化工具块表示区域，前两项为起点、后两项为区域宽度和高度
            toolsRect = new Rectangle(border, border, width * RL[1], width * RL[0]);
            toolsPostion = new Point(0, 0);                     //标志鼠标在工具条中的行列位置
            toolSelect = new Point(-1, -1);                     //标志选中的工具块行列位置
            int[,] toolsDataTmp = { { 1, 4, 8, 96, 128, 0, 2048 }, { 2, 2, 2, 2, 2, 2, 4096 }, { 2, 2, 2, 2, 2, 2, 16} };
            toolsData = toolsDataTmp;                           //各工具块对应数值
            mouseIcon = new Cursor[RL[0], RL[1]];               //初始化鼠标图像数组
            initCursors();                                      //使用工具栏中的图像创建鼠标图标

            //初始化tileMap图表示区域，位于工具栏的下方
            tileMapRect = new Rectangle(border, toolsRect.Bottom + width, width * RL[3], width * RL[2]);
            tileMapPostion = new Point(0, 0);                   //标志鼠标在tileMap中的行列位置
            tileMapData = new int[RL[2],RL[3]];                 //tileMap中的数据

            //水果数据初始化
            fruitData = new int[RL[2], RL[3]];                  //水果类型数据
            fruitDataInit();
            numOfFruit = RL[1]-1;                                //初始化水果类型，根据水果图像的数目

            bool[] select = { true, true, true, true, true, true };
            fruitSelect = select;                                //初始化选中水果

            CA = new Point[RL[2], RL[3]];                       //初始化传送接收数组
            CA_num = new int[RL[2], RL[3], 2];                  //传送接收标号
            CA_count = 0;

            comboBox4.Enabled = false;          //protocolVersion:不可用
            textBox4.Enabled = false;           //randomSeed:不可用

            UI_AutoVisible();                                 //隐藏界面中非必须的控件
            setLanguageStyle(false);

            groupBox6.Top = 229;
        }

        /// <summary>
        /// 根据控件是否可用，设置其是否可见
        /// </summary>
        private void UI_AutoVisible()
        {
            int PosY = comboBox1.Top;    //设置第一个控件的Y坐标
            PosY =  AutoVisible(comboBox1, label1, PosY);
            PosY =  AutoVisible(textBox3, label2, PosY);

            PosY =  AutoVisible(comboBox4, label4, PosY);
            PosY =  AutoVisible(textBox4, label5, PosY);
            PosY =  AutoVisible(textBox5, label6, PosY);

            PosY =  AutoVisible(textBox8, label9, PosY);
            PosY =  AutoVisible(textBox9, label10, PosY);
            PosY =  AutoVisible(textBox6, label8, PosY);
            PosY =  AutoVisible(textBox10, label11, PosY);

            PosY =  AutoVisible(textBox15, label14, PosY);
            PosY =  AutoVisible(textBox16, label17, PosY);

            companyVisible(textBox3, radioButton1);
            companyVisible(textBox16, radioButton2);
            companyVisible(textBox15, radioButton3);
            companyVisible(textBox8, checkBox31);
        }

        /// <summary>
        /// 根据控件textBox是否可用属性,设置这两个控件是否可见，
        /// 并设置下一个控件的位置
        /// </summary>
        private int AutoVisible(TextBox  textBox, Label label, int PosY)
        {
            label.Visible = textBox.Visible = textBox.Enabled;

            if (textBox.Enabled)
            {
                label.Top = textBox.Top = PosY;
                PosY += 23;
            }
            return PosY;
        }

        /// <summary>
        /// /// 根据控件textBox是否可用属性,决定是否显示选择框
        /// 以及选择框的位置
        /// </summary>
        private int AutoVisible(ComboBox comboBox, Label label, int PosY)
        {
            label.Visible = comboBox.Visible = comboBox.Enabled;
            if (comboBox.Enabled)
            {
                label.Top = comboBox.Top = PosY;
                PosY += 23;
            }
            return PosY;
        }

        /// <summary>
        /// 控件check与textBox同步显示
        /// </summary>
        private void companyVisible(TextBox textBox, RadioButton check)
        {
            check.Visible = textBox.Enabled;
            check.Top = textBox.Top+3;
        }

        private void companyVisible(TextBox textBox, CheckBox check)
        {
            check.Visible = textBox.Enabled;
            check.Top = textBox.Top + 3;
        }

        //对水果数据进行初始化
        private void fruitDataInit()
        {
            fruitData = new int[RL[2], RL[3]];                  //水果类型数据
            for (int i = 0; i < RL[2]; i++)
                for (int j = 0; j < RL[3]; j++)
                    fruitData[i, j] = -1;                       //-1进行初始化表示没有水果
        }

        /// <summary>
        /// 定时刷新界面的显示
        /// </summary>
        private void timer1_Tick(object sender, EventArgs e)
        {
            refreashpictureBox1();          
            timer1.Enabled = false;
        }

        /// <summary>
        /// 鼠标移动事件，获取鼠标在工具栏、或tileMap中的动态位置，
        /// 并根据所在位置的不同设置不同的鼠标显示图标
        /// </summary>
        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            //获取鼠标的位置
            if (toolsRect.Contains(e.Location))                 //在工具条中的位置
            {
                toolsPostion.Y = (e.X - toolsRect.X) / width;
                toolsPostion.X = (e.Y - toolsRect.Y) / width;
            }
            else if (tileMapRect.Contains(e.Location))          //在tileMap中的位置
            {
                tileMapPostion.Y = (e.X - tileMapRect.X) / width;
                tileMapPostion.X = (e.Y - tileMapRect.Y) / width;

                textBox18.Text = tileMapPostion.ToString();
            }
            else
            {                                                   //在其它的位置，清除在工具栏、或tileMap中的动态位置
                toolsPostion.X = -1;
                tileMapPostion.X = - 1;
            }

            //在tileMap区域显示工具栏图标，其它区域显示默认图标
            if (tileMapRect.Contains(e.Location))
            {
                if (toolSelect.X != -1 && pictureBox1.Cursor == Cursors.Default)    //如果选中了工具块，且鼠标图标还是默认图标
                {
                    if (toolSelect.Y == RL[1] - 1 && toolSelect.X < 2) 
                        toolSelect.X = CA_count % 2;                                //如果选中传送或接收块，则根据CA_count计数值决定为传送还是接收块

                    pictureBox1.Cursor = mouseIcon[toolSelect.X, toolSelect.Y];     //则设置鼠标显示图标，为选中工具块
                }
            }
            else pictureBox1.Cursor = Cursors.Default;          //显示默认鼠标图标
        }

        /// <summary>
        /// 鼠标单击事件，在工具栏单击时，记录选中的工具位置；
        /// 在tileMap上单击时，在对应的块位置记录工具块数据
        /// </summary>
        private void pictureBox1_Click(object sender, EventArgs e)
        {
            if(toolsPostion.X != -1)                            //鼠标位于工具栏上
            {
                //对水果工具块执行该逻辑
                if (toolsPostion.X == 1 && 0 <= toolsPostion.Y && toolsPostion.Y <= 5)
                {
                    if (fruitSelect[toolsPostion.Y])                //如果该水果块为可用状态
                    {
                        toolSelect.X = toolsPostion.X;              //记录在工具栏中的位置
                        toolSelect.Y = toolsPostion.Y;
                    }
                    else
                    {
                        toolSelect.X = -1;                          //未选中工具块
                        toolSelect.Y = -1;
                    }
                }
                //对其他工具块
                else
                {
                    toolSelect.X = toolsPostion.X;                  //记录在工具栏中的位置
                    toolSelect.Y = toolsPostion.Y;
                }

                textBox17.Text = toolSelect.ToString();             //显示选中工具块位置
            }
            else if (tileMapPostion.X != -1 && toolSelect.X != -1)              //鼠标位于tileMap上，且选中了工具块
            {
                int toolNum = toolsData[toolSelect.X, toolSelect.Y];            //获取选中工具块的数值
                int tileData = tileMapData[tileMapPostion.X, tileMapPostion.Y]; //获取鼠标处tileMap块对应的数据

                tileData = toolDataConstration(toolNum, tileData, toolSelect.X);//根据工具块，对块数据进行相应处理
                tileMapData[tileMapPostion.X, tileMapPostion.Y] = tileData;     //记录更新后的数据到对应的位置

                //水果类型数据校验
                if ((tileData & 2) == 0)                                        //如果块中不含水果属性，则清除水果类型
                    fruitData[tileMapPostion.X, tileMapPostion.Y] = -1;
                if (toolSelect.X == 1 && toolSelect.Y != RL[1]-1)               //如果是水果，则修改水果类型， 
                    fruitData[tileMapPostion.X, tileMapPostion.Y] = toolSelect.Y;


                drawTile(tileMapPostion.X, tileMapPostion.Y, tileData);         //重绘

                
                //refreashpictureBox1();                          //刷新显示
            }
        }

        //在传送标识数组中寻找数值num的位置,找到返回对应坐标位置
        private Point findConverySite(int num)
        {
            for (int i = 0; i < RL[2]; i++)
                for (int j = 0; j < RL[3]; j++)
                    if (CA_num[i, j, 0] == num) 
                        return new Point(i, j);
            return new Point();
        }

        /// <summary>
        /// 工具块之间的数据约束
        /// </summary>
        private int toolDataConstration(int toolNum, int tileData0, int line)
        {
            int tileData = tileData0;

            //根据各工具块对块数据做相应处理
            if (toolNum == 0)
            {
                if ((tileData & 2048) != 0)             //清除的为传送块
                {
                    //传送块操作
                    CA_num[tileMapPostion.X, tileMapPostion.Y, 0] = 0;      //清除传送块标识值
                    Point accept = CA[tileMapPostion.X, tileMapPostion.Y];
                    CA[tileMapPostion.X, tileMapPostion.Y] = new Point();  //坐标清空

                    //接收块操作
                    tileMapData[accept.X, accept.Y] &= (~4096);             //接收块去除接收属性
                    CA_num[accept.X, accept.Y, 1] = 0;                      //清除接收块接收属性标识值
                    drawTile(accept.X, accept.Y, tileMapData[accept.X, accept.Y]); //重绘接收块
                }
                if ((tileData & 4096) != 0)             //清除的为接收块
                {
                    //接收块操作
                    int num = CA_num[tileMapPostion.X, tileMapPostion.Y, 1];//记录接收标识值
                    Point convery = findConverySite(num);                   //获取传送位置
                    CA_num[tileMapPostion.X, tileMapPostion.Y, 1] = 0;      //清除接收属性

                    //传送块操作
                    tileMapData[convery.X, convery.Y] &= (~2048);       //传送块去除接收属性
                    CA_num[convery.X, convery.Y, 0] = 0;                //清除传送块标识值
                    CA[convery.X, convery.Y] = new Point();             //坐标清空
                    drawTile(convery.X, convery.Y, tileMapData[convery.X, convery.Y]); //重绘传送块
                }

                tileData = 0;             //橡皮工具
            }
            else
            {
                if (toolSelect.X == 0 || toolSelect.X == 1) //工具栏前两行
                {
                    //其它工具块，数据关系约束
                    if (toolSelect.Y == RL[1] - 1)          //为传送或接收块属性
                    {
                        if (tileData0 == 0) toolNum = 0;    //空块不可传送或接收
                        else
                        {
                            if ((tileData0 & toolNum) == 0) //如果当前块中不含toolNum属性，则添加
                            {
                                pictureBox1.Cursor = Cursors.Default;          //显示默认鼠标图标

                                if (line < 2) CA_num[tileMapPostion.X, tileMapPostion.Y, line] = CA_count / 2 + 1; //记录传送、接收标号
                                if (line == 0) preSite = new Point(tileMapPostion.X, tileMapPostion.Y);             //记录前一处传送位置的坐标
                                else if (line == 1) CA[preSite.X, preSite.Y] = new Point(tileMapPostion.X, tileMapPostion.Y); //在传送坐标处，记录当前接收位置

                                CA_count++;                 //计数值递增
                            }
                            else toolNum = 0;               //已有该属性
                        }
                    }
                    else if (line == 1)
                    {
                        toolNum = 2;                        //水果 统一使用2代替
                        if ((tileData & 32) != 0 && (tileData & 64) != 0) tileData -= 96;//有石块属性则清除
                    }
                    else
                    {
                        if (toolNum == 4) { if ((tileData & 8) != 0) tileData -= 8; }       //冰
                        else if (toolNum == 8) { if ((tileData & 4) != 0) tileData -= 4; }  //双层冰
                        else if (toolNum == 96)                                             //石块
                        {
                            if ((tileData & 2) != 0)                                        //去除水果属性
                            { tileData -= 2; tileData &= 65535; }
                            if ((tileData & 128) != 0) tileData -= 128;                     //去除锁定属性
                            //if ((tileData & 16) != 0) tileData -= 16;                       //去除birth属性
                            if ((tileData & 2048) != 0) tileData -= 2048;                   //去除传送属性
                            if ((tileData & 4096) != 0) tileData -= 4096;                   //去除接收属性
                        }
                        else if (toolNum == 128) { if ((tileData & 2) == 0) toolNum = 0; }  //锁定，没有水果属性不锁定
                    }

                    tileData |= toolNum;                    //将工具块的值添加到tileMap块数据中
                }
                else if (toolSelect.X == 2)                 //工具栏第3行
                {
                    if ((toolNum & 16) != 0)                //最后的birth块
                    {
                        if (tileData == 0) toolNum = 0;     //空块不添加生成属性
                    }
                    else if ((toolNum & 2) != 0)
                    {
                        if (0 <= toolSelect.Y && toolSelect.Y <= 2)     //第3行前3个工具块
                        {
                            fruitData[tileMapPostion.X, tileMapPostion.Y] = toolSelect.Y + 40; //三个块的水果类型分别为40、41、42
                        }
                        else if (3 <= toolSelect.Y && toolSelect.Y <= 5)//第3行另3个工具块
                        {
                            if (fruitData[tileMapPostion.X, tileMapPostion.Y] < 40 && (tileData & 2) != 0)
                            {
                                int tmp = fruitData[tileMapPostion.X, tileMapPostion.Y] % 10 + (toolSelect.Y - 2) * 10; //保持原有水果类型
                                fruitData[tileMapPostion.X, tileMapPostion.Y] = tmp;
                            }
                            else toolNum = 0;
                        }

                        if ((tileData & 32) != 0 && (tileData & 64) != 0) tileData -= 96;//有石块属性则清除
                    }

                    tileData |= toolNum;                    //将工具块的值添加到tileMap块数据中
                }
            }

            return tileData;
        }

        /// <summary>
        /// 使用工具栏中的图像创建鼠标显示图标，初始创建所有图标
        /// </summary>
        private void initCursors()
        {
            for (int i = 0; i < RL[0]; i++)
                for (int j = 0; j < RL[1]; j++)
                    mouseIcon[i, j] = GetCursor(toolsPic[i, j], (int)(width * 0.75));

        }

        /// <summary>
        /// 获取用图像pic，按指定大小width创建鼠标图标
        /// </summary>
        public Cursor GetCursor(Image pic, int width)
        {
            Bitmap icon = new Bitmap(width, width);             //按指定大小创建位图
            Graphics g = Graphics.FromImage(icon);              //从位图创建Graphics对象
            g.Clear(Color.FromArgb(0, 0, 0, 0));
            g.DrawImage(pic, 0, 0, icon.Width, icon.Height);    //绘制Image到位图

            //Bitmap icon = new Bitmap(tiles[toolsPostion.Y - 1]);

            try { return new Cursor(icon.GetHicon()); }         //从位图创建鼠标图标
            catch (Exception e) { return Cursors.Default; }
        }

        private void button8_Click(object sender, EventArgs e)
        {
            String str = "";

            tileMapData = tileMapDataSetAttr(tileMapData, RL[2], RL[3]);

            for (int i = 0; i < RL[2]; i++)
            {
                for (int j = 0; j < RL[3]; j++)
                {
                    str += tileMapData[i, j];
                    if (j < RL[3] - 1) str += ", ";
                }
                if (i < RL[2] - 1) str += ";\r\n";
            }

            textBox2.Text = str;

            textBox7.Text = portalsToString();

            //去除最后的一个';'
            String tmp = textBox7.Text.Trim();
            int index = tmp.LastIndexOf(';');
            if (index >= tmp.Length - 3 && index!=-1) textBox7.Text = tmp.Substring(0, tmp.LastIndexOf(';'));
        }

        //导出传送数组中的数据，转换为目标样式的字符串
        private String portalsToString()
        {
            String str = "";
            String tail = "";
            Point pTmp;
            for (int j = 0; j < RL[3]; j++)
            {
                for (int i = 0; i < RL[2]; i++)
                {
                    pTmp = CA[i, j];

                    if (!pTmp.IsEmpty)
                        str += ("" + j + "," + i + "." + pTmp.Y + "," + pTmp.X + ";" + "\r\n");
                 }
                
            }
            return str;
        }


        /// <summary>
        /// 对tileMap中的数据进行处理，根据数据所在位置设置一些相关属性
        /// tileMapData的行列数分别为R、L
        /// </summary>
        private int[,] tileMapDataSetAttr(int[,] data, int R, int L)
        {
            int[,] tmp = new int[R, L];

            if (textBox7.Text.Trim().Equals("") && CA_count == 0) //如果传送接收属性为空，则自动生成传送属性
                tmp = setPortalsFromTileData(data, R, L);
            else tmp = data;                                    //否则保持原值        


            ////birth属性设置
            //for (int j = 0; j < L; j++)                         //对于每一列数据
            //{
            //    for (int i = 0; i < R; i++)
            //    {
            //        if ((tmp[i, j] & 2) != 0)                   //每列从上到下，第一个有水果属性的块
            //        {
            //            tmp[i, j] |= 16;                        //水果消去后，可生成
            //            break;                                  //退出该列循环
            //        }
            //    }
            //}

            //bottom属性设置
            for (int j = 0; j < L; j++)                         //对于每一列数据
            {
                for (int i = R-1; i >= 0; i--)
                {
                    if ((tmp[i, j] & 2) != 0)                           //每列从下到上，第一个有水果属性的块
                    {
                        if ((tmp[i, j] & 2048) == 0) tmp[i, j] |= 512;      //没有传送属性，则为其添加bottom属性
                        else tmp[i, j] &= (~512);                           //有传送属性去除bottom属性
                        break;                                  //退出该列循环
                    }
                }
            }
            return tmp;
        }


        //从tileMap数据自动生成传送属性，生成规则为从上向下传送，穿过空位置
        private int[,] setPortalsFromTileData(int[,] data, int R, int L)
        {
            int[,] tmp = new int[R, L];

            //传送、接收属性设置
            for (int j = 0; j < L; j++)        //对于每一列数据
            {
                int pre = -1;                              //pre记录非0数据的行位置
                for (int i = 0; i < R; i++)
                {
                    tmp[i, j] = data[i, j];

                    if (tmp[i, j] != 0)
                    {   //(若存在前一个非0项 且 与其不相邻)，则构建portoals项，前一个非0位置指向当前非0位置
                        if (pre != -1 && pre + 1 != i) // str += ((str.Equals("") ? "" : ";") + j + "," + pre + "." + j + "," + i);
                        {
                            //上部的块需拥有水果属性，下部的块需拥有水果或冰属性则可接收
                            //if ( ((tmp[pre, j] & 2) != 0  || (tmp[pre, j] & 4) != 0 || (tmp[pre, j] & 8) != 0)
                            //    && ((tmp[i, j] & 2) != 0 || (tmp[i, j] & 4) != 0 || (tmp[i, j] & 8) != 0) )

                            //上下均有水果属性才可传送
                            //if ((tmp[pre, j] & 2) != 0 && (tmp[i, j] & 2) != 0 )
                            {
                                if ((tmp[pre, j] & 2048) == 0 && (tmp[i, j] & 4096) == 0)   //上未传送且下未接收
                                {
                                    tmp[pre, j] |= 2048;                        //可传送
                                    tmp[i, j] |= 4096;                          //可接收

                                    CA_num[pre, j, 0] = CA_count / 2 + 1;       //记录传送标号
                                    CA_num[i, j, 1] = CA_count / 2 + 1;         //记录接收标号

                                    CA[pre, j] = new Point(i, j);               //在传送位置处记录当前接收位置

                                    CA_count += 2;                              //数值累计
                                }
                            }
                        }
                        pre = i;                                //记录非0项位置
                    }
                }
            }

            return tmp;
        }


        private void button9_Click(object sender, EventArgs e)
        {
            int[][] tmp = getTwoDimentionData(textBox2.Text);   //读取tileMap数据到数组中
            if (tmp == null) return;

            for (int i = 0; i < RL[2]; i++)
            {
                for (int j = 0; j < RL[3]; j++)
                {
                    tileMapData[i, j] = tmp[i][j];              //数据转存到tileMapData中
                }
            }

            ExtraCA();                                          //提取传送接收数据，并保存到tileMap中

            refreashpictureBox1();                              //刷新界面的显示
        }

        //提取传送接收数据
        private void ExtraCA()
        {
            try
            {
                CA = new Point[RL[2], RL[3]];                  //初始化传送接收数组
                CA_num = new int[RL[2], RL[3], 2];             //传送接收标号
                CA_count = 0;

                int[][] portoals = getPortals(textBox7.Text);  //读取portoals数据
                if (portoals == null) return;                  //无该属性则返回

                int x1, y1, x2 = 0, y2;
                for (int i = 0; i < portoals.Length; i++)
                {
                    x1 = portoals[i][1];                        //传送坐标
                    y1 = portoals[i][0];

                    x2 = portoals[i].Length == 4 ? portoals[i][3] : portoals[i][4];                        //接收坐标
                    y2 = portoals[i].Length == 4 ? portoals[i][2] : portoals[i][3];

                    CA[x1, y1] = new Point(x2, y2);             //在传送位置处记录接收位置坐标

                    if (CA_num[x1, y1, 0] == 0)
                    {
                        CA_num[x1, y1, 0] = CA_count / 2 + 1;   //记录传送标号
                        CA_num[x2, y2, 1] = CA_count / 2 + 1;   //记录接收标号
                        CA_count += 2;                          //数值累计

                        tileMapData[x1, y1] |= 2048;            //校验传送属性到数据块中
                        tileMapData[x2, y2] |= 4096;            //校验接收属性到数据块中
                    }
                }
            }
            catch (Exception eX)
            {
                MessageBox.Show("函数 ExtraCA() 出错！");
            }
        }

        private void button10_Click(object sender, EventArgs e)
        {
            refreashpictureBox1();                              //刷新界面的显示
        }


        /// <summary>
        /// 水果种类数目改变则更新相应数值到变量
        /// </summary>
        private void textBox3_TextChanged(object sender, EventArgs e)
        {
            if (fruitMutex)
            {
                fruitMutex = false;

                String strNum = textBox3.Text.Trim();
                try { numOfFruit = strNum.Equals("") ? RL[1]-1 : Int32.Parse(strNum); }
                catch (Exception ex) { numOfFruit = RL[1]-1; }

                numOfFruit = RL[1]-1 < numOfFruit ? RL[1]-1 : numOfFruit;   //保留较小的水果类型值

                if (numOfFruit <= 0) numOfFruit = 6;                        //水果种类数校验

                checkSelect(numOfFruit);                                    //根据水果类型数目选中相同数目的水果

                drawTools();                                                //刷新工具栏的显示
                pictureBox1.Cursor = Cursors.Default;                       //显示默认图标
                toolSelect.X = -1;                                          //该水果未被选中

                fruitMutex = true;
            }
        }

        //获取6种水果的选中状态
        private bool[] fruitsSelect()
        { 
            bool[] select = { checkBox16.Checked, checkBox17.Checked, checkBox18.Checked, 
                                 checkBox19.Checked, checkBox20.Checked, checkBox21.Checked };
            return select;
        }

        //获取选中的水果数目
        private int selectNum()
        {
            bool[] select = fruitsSelect();             //获取水果选中状态
            int num = 0;
            for (int i = 0; i < select.Length; i++)     //获取选中的水果数目
                if (select[i]) num++;

            return num;
        }

        //根据给定的水果数目，校验选中的水果数目，若不足则自行补足选中，若多选了则自行剔除多余的最后几项
        private void checkSelect(int fruitsNum)
        {
            int subNum = fruitsNum - selectNum();       //获取要选中的数目与已选中数目之间的差值
            int count = 0;                              //记录选中项的数目
            bool[] select = fruitSelect;                //获取水果选中状态

            CheckBox[] fruitCheck = { checkBox16, checkBox17, checkBox18, checkBox19, checkBox20, checkBox21}; 

            if(subNum > 0)                              //补选若干个水果
            {
                for (int i = 0; i < select.Length; i++)
                {
                    if (!select[i])
                    {
                        fruitCheck[i].Checked = true;   //选中
                        subNum--;
                        if (subNum == 0) return;
                    }
                }
            }
            else if(subNum < 0)                         //去除多选的水果
            {
                for (int i = 0; i < select.Length; i++)
                {
                    if (count < fruitsNum) { if (select[i]) count++; }
                    else if (select[i]) fruitCheck[i].Checked = false;  //取消选中
                }
            }

            fruitSelect = fruitsSelect();                               //获取水果选中状态
        }

        //水果选择
        private void checkBox16_CheckedChanged(object sender, EventArgs e)
        {
            if (fruitMutex)
            {
                fruitMutex = false;

                textBox3.Text = selectNum().ToString(); //根据水果选中状态，修改水果种类数
                fruitSelect = fruitsSelect();           //获取水果选中状态
                numOfFruit = selectNum();               //选中水果数目变动

                drawTools();                                                //刷新工具栏的显示
                pictureBox1.Cursor = Cursors.Default;                       //显示默认图标
                toolSelect.X = -1;                                          //该水果未被选中

                fruitMutex = true;
            }
        }

        //根据数值num判定水果类型
        private int getFruitType(int num)
        {
            if (fruitSelect[num]) return num;           //如果该水果处于可用状态，直接返回该类型
            else
            {
                int count = 0;
                for (int i = 0; i < fruitSelect.Length; i++)
                {
                    if (fruitSelect[i])                 //该水果可选中
                    {
                        if (count == num) return i;     //返回该种类型
                        else count++;
                    }
                }

                //随机生成水果类型
                int typeNum = (int)Math.Floor(rnd.NextDouble() * numOfFruit);
                return getFruitType(typeNum);
            }
        }

        private void Form1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            setLanguageStyle(!isEnglish);    //设置显示样式
        }


        //更新界面的显示样式
        private void setLanguageStyle(bool isEnglish)
        {
            if (isEnglish == this.isEnglish) return;    //如果当前已经是该样式，则无需切换

            Label[] labels = { label1, label2, label4, label5, label6, label9, label10, label8, label11, label14, label17, label3, label7 };

            String[] labelTextEN = {"gameModeName:", "numberOfColours:", "protocolVersion:", "randomSeed:", "scoreTargets:", "ingredientSpawnDensity:", "ingredients:", 
"moveLimit:", "numIngredientsOnScreen:", "ingredientsFruit:", "levelDifficulty:", "portals:", "tileMap: "};
            String[] labelTextCN = { "游戏模式:", "水果种类数:", "版本号:", "随机数种子:", "目标分数:", "待收集步距:", "待收集物品:", "总步数:", "待收集数目:", "收集水果:", "关卡难度:", "传送:", "图块:" };

            String[] text = isEnglish ? labelTextEN : labelTextCN;              //选择样式
            for (int i = 0; i < text.Length; i++) labels[i].Text = text[i];     //设置对应文本

            button9.Text = "从" + label7.Text.Trim().Replace(":", "") + "导入";
            button8.Text = "导出到" + label7.Text.Trim().Replace(":", "");

            //更新关卡模式样式
            String[] modeTextEN = { "Classic moves", "Classic", "Drop down", "Drop down fruit", "Light up" };
            String[] modeTextCN = { "计步模式", "计时模式", "收集物品", "收集水果", "消除冰块" };
            String[] modeText = isEnglish ? modeTextEN : modeTextCN;             //选择样式

            int selceteI = comboBox1.SelectedIndex;
            comboBox1.Items.Clear();
            for (int i = 0; i < modeText.Length; i++) comboBox1.Items.Add(modeText[i]);     //设置对应文本
            comboBox1.SelectedIndex = selceteI;

            this.isEnglish = isEnglish;                 //更新语言样式标识
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            constract(checkBox1, checkBox9, true);      //非空位置可传送
            constract(checkBox1, checkBox10, true);     //非空位置可接收
            CheckedChanged(null, null);
        }

        private void checkBox14_CheckedChanged(object sender, EventArgs e)
        {
            button10_Click(null, null);
        }

        private void 新建ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            刷新ToolStripMenuItem_Click(null, null);    //保存现有数据

            fruitDataInit();
            tileMapData = new int[RL[2], RL[3]];                //tileMap中的数据
            CA = new Point[RL[2], RL[3]];                       //初始化传送接收数组
            CA_num = new int[RL[2], RL[3], 2];                  //传送接收标号
            CA_count = 0;                                       //清除计数值
            textBox7.Text = "";
            textBox2.Text = "";

            refreashpictureBox1();                              //刷新界面的显示
        }

        private void textBox13_Click(object sender, EventArgs e)
        {
            textBox13.SelectAll();
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Left) textBox13.Text = (curFilesNum - 1).ToString();
            else if (e.KeyCode == Keys.Right) textBox13.Text = (curFilesNum + 1).ToString();
            else if (e.KeyCode == Keys.Down) textBox13.Text = (curFilesNum - (OpendFilesName.Length - 1) / 5).ToString();
            else if (e.KeyCode == Keys.Up) textBox13.Text = (curFilesNum + (OpendFilesName.Length - 1) / 5).ToString();

            button1_Click_1(null, null);
        }

        private void button11_Click(object sender, EventArgs e)
        {
            textBox13.Text = (curFilesNum - 1).ToString();
            button1_Click_1(null, null);
        }

        private void button12_Click(object sender, EventArgs e)
        {
            textBox13.Text = (curFilesNum + 1).ToString();
            button1_Click_1(null, null);
        }

        private void button13_Click(object sender, EventArgs e)
        {
            textBox13.Text = (curFilesNum - (OpendFilesName.Length - 1) / 5).ToString();
            button1_Click_1(null, null);
        }

        private void button14_Click(object sender, EventArgs e)
        {
            textBox13.Text = (curFilesNum + (OpendFilesName.Length - 1) / 5).ToString();
            button1_Click_1(null, null);
        }

        private void Form1_MouseEnter(object sender, EventArgs e)
        {
        }

        private bool trackBarMutex = true;
        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            if (trackBarMutex)
            {
                trackBarMutex = false;

                timer2_Tick(null, null);

                trackBarMutex = true;
            }
        }

        //更新难度数据
        private void textBox16_DoubleClick(object sender, EventArgs e)
        {
            //初始难度
            int onePercent = trackBar1.Maximum / 100;
            float value1 = (float)trackBar1.Value / onePercent;
            textBox16.Text = value1.ToString() + ", " + (100 - value1).ToString() + "; ";

            //游戏难度
            float percent2 = (float)trackBar2.Value / trackBar2.Maximum;                            //难度所占比例
            int p1_2 = trackBar2.Value + (int)((trackBar2.Maximum - trackBar2.Value) * percent2);   //p1和p2的总难度值
            int p1 = (int)(p1_2 * percent2);                                                        //p1的难度值
            int p2 = p1_2 - p1;                                                                     //p2的难度值
            float value2_1 = (float)p1 / onePercent;
            float value2_2 = (float)p2 / onePercent;
            textBox16.Text += value2_1.ToString() + ", " + value2_2.ToString();
        }

        //关卡难度值变动，难度显示到滚动条中
        private void textBox16_TextChanged(object sender, EventArgs e)
        {
            try
            {
                if (trackBarMutex)
                {
                    trackBarMutex = false;

                    //初始难度显示到滚动条
                    String[] tmp = textBox16.Text.Replace(';', ',').Split(',');
                    float[] num = new float[4];
                    for (int i = 0; i < 4; i++)
                        num[i] = float.Parse(tmp[i].Trim());

                    //输入数值校验
                    if (num[0] > 100) num[0] = 100;
                    else if (num[0] < 0) num[0] = 0;
                    if (num[1] > 100 - num[0] || num[0] + num[1]<100) num[1] = 100 - num[0];
                    else if (num[1] < 0) num[1] = 0;

                    if (num[2] > 100) num[2] = 100;
                    else if (num[2] < 0) num[2] = 0;
                    if (num[2] + num[3] > 100) num[3] = 100 - num[2];
                    else if (num[3] < 0) num[3] = 0;

                    int onePercent = trackBar1.Maximum / 100;
                    trackBar1.Value = (int)(num[0] * onePercent);


                    //游戏难度显示到滚动条
                    int minValue = (int)(onePercent * num[2]);              //下限
                    int maxValue = (int)(onePercent * (num[2] + num[3]));   //上限

                    int value = (minValue + maxValue) / 2;                  //取中值
                    if (value > trackBar2.Maximum) value = trackBar2.Maximum;//数值校验
                    trackBar2.Value = value;

                    int flag = checkEqual2(num[2]);

                    while (flag != 0 && maxValue - minValue > 1)            //未取到概率值，且上下限步近似相等则继续
                    {
                        if (flag > 0) maxValue = trackBar2.Value;           //值较大，向下移动
                        else minValue = trackBar2.Value;                    //值较小，向上移动

                        value = (minValue + maxValue) / 2;                  //取中值
                        if (value > trackBar2.Maximum) value = trackBar2.Maximum;//数值校验
                        trackBar2.Value = value;

                        flag = checkEqual2(num[2]);
                    }


                    //trackBar2.Value = (int)(onePercent * (num[2] + num[3]));
                    //for (int i = trackBar2.Value; i > 0; i--)
                    //{
                    //    trackBar2.Value = i;
                    //    if (checkEqual(num[2])) break;
                    //}

                    trackBarMutex = true;
                }
            }
            catch (Exception ex)
            { trackBarMutex = true; }
        }

        //判断该比例值时，是否取得num
        private int checkEqual2(float num)
        {
            int onePercent = trackBar1.Maximum / 100;

            float percent2 = (float)trackBar2.Value / trackBar2.Maximum;                            //难度所占比例
            int p1_2 = trackBar2.Value + (int)((trackBar2.Maximum - trackBar2.Value) * percent2);   //p1和p2的总难度值
            int p1 = (int)(p1_2 * percent2);                                                        //p1的难度值
            int p2 = p1_2 - p1;                                                                     //p2的难度值
            float value2_1 = (float)p1 / onePercent;

            if (value2_1 == num) return 0;
            else if (value2_1 > num) return 1;
            else return -1;
        }

        //判断该比例值时，是否取得num
        private bool checkEqual(float num)
        {
            int onePercent = trackBar1.Maximum / 100;

            float percent2 = (float)trackBar2.Value / trackBar2.Maximum;                            //难度所占比例
            int p1_2 = trackBar2.Value + (int)((trackBar2.Maximum - trackBar2.Value) * percent2);   //p1和p2的总难度值
            int p1 = (int)(p1_2 * percent2);                                                        //p1的难度值
            int p2 = p1_2 - p1;                                                                     //p2的难度值
            float value2_1 = (float)p1 / onePercent;

            if (value2_1 == num) return true;
            else return false;
        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            textBox16_DoubleClick(null, null);
            timer2.Enabled = false;
        }

        //选中单选按钮显示对应的控件组
        private void radioButton1_CheckedChanged(object sender, EventArgs e)
        {
            RadioButton[] radio = { radioButton1, radioButton2, radioButton3 };
            GroupBox[] group = { groupBox6, groupBox7, groupBox8 };

            for (int i = 0; i < radio.Length; i++)
                group[i].Visible = radio[i].Checked;
        }


        //重新导出所有打开的关卡数据
        private void 导出全部ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveProcess = 0;
            timer3.Enabled = true;
        }


        private void timer3_Tick(object sender, EventArgs e)
        {
            if (mutexLoadFinish)
            {
                mutexLoadFinish = false;            //不可再次保存
                SaveToFileMute(FormatEdit());       //载入完成，则静默保存
            }
            if (mutexSaveFinish)
            {
                mutexSaveFinish = false;            //不可再次跳转
                button12_Click(null, null);         //保存完成，则跳转载入下一关
                saveProcess++;
            }

            if (saveProcess == OpendFilesName.Length - 1)
            {
                timer3.Enabled = false;
                MessageBox.Show("成功导出所有数据！");
            }
        }

        //是否随机生成选择框
        private void checkBox30_CheckedChanged(object sender, EventArgs e)
        {
            panel1.Visible = checkBox30.Checked;
        }

        //收集水果栏中水果种类选择后，显示对应的文本框
        private void checkBox29_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox[] check = { checkBox29, checkBox28, checkBox27, checkBox26, checkBox25, checkBox24 };
            TextBox[] txt1 = { textBox19, textBox20, textBox21, textBox22, textBox23, textBox24 };
            TextBox[] txt2 = { textBox30, textBox29, textBox28, textBox27, textBox26, textBox25 };

            for (int i = 0; i < check.Length; i++)
                txt2[i].Visible = txt1[i].Visible = check[i].Checked;
        }

        //收集水果栏显示状态改变时，更新其显示内容
        private void groupBox8_VisibleChanged(object sender, EventArgs e)
        {
            checkBox30_CheckedChanged(null, null);
            checkBox29_CheckedChanged(null, null);
        }

        //将收集水果中的数据保存到编辑器
        private void button15_Click(object sender, EventArgs e)
        {
            CheckBox[] check = { checkBox29, checkBox28, checkBox27, checkBox26, checkBox25, checkBox24 };
            TextBox[] txt1 = { textBox19, textBox20, textBox21, textBox22, textBox23, textBox24 };
            TextBox[] txt2 = { textBox30, textBox29, textBox28, textBox27, textBox26, textBox25 };

            String str = "";
            for (int i = 0; i < check.Length; i++)
            {
                if (check[i].Checked)
                {
                    if (txt1[i].Text.Trim().Equals("")) txt1[i].Text = "0";
                    if (txt2[i].Text.Trim().Equals("") && checkBox30.Checked) txt2[i].Text = "0";
                }

                str += (str.Equals("") || !check[i].Checked) ? "" : "; ";
                str += !check[i].Checked ? "" : (i.ToString() + ", " + txt1[i].Text + (checkBox30.Checked ? (", " + txt2[i].Text) : ""));
            }

            textBox15.Text = str;
        }

        //更新编辑器中的数据到收集水果栏
        private void textBox15_DoubleClick(object sender, EventArgs e)
        {
            try
            {

                if (textBox15.Text.Trim().Equals("")) return;

                //将文本字符串转换为数据存储到数组中
                String[] str1 = textBox15.Text.Trim().Split(';');
                int[][] num = new int[str1.Length][];

                for (int i = 0; i < str1.Length; i++)
                {
                    String[] str2 = str1[i].Split(',');
                    num[i] = new int[str2.Length];

                    for (int j = 0; j < str2.Length; j++)
                    {
                        num[i][j] = Int32.Parse(str2[j].Trim());
                    }
                }

                //初始化选中
                CheckBox[] check = { checkBox29, checkBox28, checkBox27, checkBox26, checkBox25, checkBox24 };
                TextBox[] txt1 = { textBox19, textBox20, textBox21, textBox22, textBox23, textBox24 };
                TextBox[] txt2 = { textBox30, textBox29, textBox28, textBox27, textBox26, textBox25 };

                for (int i = 0; i < check.Length; i++)
                    check[i].Checked = false;

                for (int i = 0; i < num.Length; i++)
                {
                    check[num[i][0]].Checked = true;
                    txt1[num[i][0]].Text = num[i][1].ToString();
                    if (!checkBox30.Checked) txt2[num[i][0]].Text = num[i].Length > 2 ? num[i][2].ToString() : "0";
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("更新数据到收集水果栏出错！/n位置：textBox15_DoubleClick");
            }
        }

        private void Form1_SizeChanged(object sender, EventArgs e)
        {
            timer1.Enabled = true;
        }






        ////设置鼠标图标
        //Bitmap icon = new Bitmap(tiles[toolsPostion.Y - 1]);
        ////Bitmap a = (Bitmap)Bitmap.FromFile("1.png");
        //SetCursor(icon, new Point(16, 36)); //new Point() 定义鼠标的可用点位置。

        ////设置鼠标函数
        //public void SetCursor(Bitmap cursor, Point hotPoint)
        //{
        //    int hotX = hotPoint.X;
        //    int hotY = hotPoint.Y;
        //    Bitmap myNewCursor = new Bitmap(cursor.Width * 2 - hotX, cursor.Height * 2 - hotY);
        //    Graphics g = Graphics.FromImage(myNewCursor);
        //    g.Clear(Color.FromArgb(0, 0, 0, 0));
        //    g.DrawImage(cursor, cursor.Width - hotX, cursor.Height - hotY, cursor.Width, cursor.Height);

        //    this.Cursor = new Cursor(myNewCursor.GetHicon());

        //    g.Dispose();
        //    myNewCursor.Dispose();
        //}
    }
}

//SelectText(textBox2,selectionStart, selectionLength);